diff --git a/src/org/oscim/core/MercatorProjection.java b/src/org/oscim/core/MercatorProjection.java index 8406e48b..b9e2df14 100644 --- a/src/org/oscim/core/MercatorProjection.java +++ b/src/org/oscim/core/MercatorProjection.java @@ -44,10 +44,12 @@ public final class MercatorProjection { public static final double LONGITUDE_MIN = -LONGITUDE_MAX; /** - * Calculates the distance on the ground that is represented by a single pixel on the map. + * Calculates the distance on the ground that is represented by a single + * pixel on the map. * * @param latitude - * the latitude coordinate at which the resolution should be calculated. + * the latitude coordinate at which the resolution should be + * calculated. * @param zoomLevel * the zoom level at which the resolution should be calculated. * @return the ground resolution at the given latitude and zoom level. @@ -58,7 +60,8 @@ public final class MercatorProjection { } /** - * Converts a latitude coordinate (in degrees) to a pixel Y coordinate at a certain zoom level. + * Converts a latitude coordinate (in degrees) to a pixel Y coordinate at a + * certain zoom level. * * @param latitude * the latitude coordinate that should be converted. @@ -79,7 +82,8 @@ public final class MercatorProjection { } /** - * Converts a latitude coordinate (in degrees) to a tile Y number at a certain zoom level. + * Converts a latitude coordinate (in degrees) to a tile Y number at a + * certain zoom level. * * @param latitude * the latitude coordinate that should be converted. @@ -103,7 +107,8 @@ public final class MercatorProjection { /** * @param longitude * the longitude value which should be checked. - * @return the given longitude value, limited to the possible longitude range. + * @return the given longitude value, limited to the possible longitude + * range. */ public static double limitLongitude(double longitude) { return Math.max(Math.min(longitude, LONGITUDE_MAX), LONGITUDE_MIN); @@ -120,7 +125,8 @@ public final class MercatorProjection { } /** - * Converts a longitude coordinate (in degrees) to a pixel X coordinate at a certain zoom level. + * Converts a longitude coordinate (in degrees) to a pixel X coordinate at a + * certain zoom level. * * @param longitude * the longitude coordinate that should be converted. @@ -138,7 +144,8 @@ public final class MercatorProjection { } /** - * Converts a longitude coordinate (in degrees) to the tile X number at a certain zoom level. + * Converts a longitude coordinate (in degrees) to the tile X number at a + * certain zoom level. * * @param longitude * the longitude coordinate that should be converted. @@ -151,7 +158,8 @@ public final class MercatorProjection { } /** - * Converts a pixel X coordinate at a certain zoom level to a longitude coordinate. + * Converts a pixel X coordinate at a certain zoom level to a longitude + * coordinate. * * @param pixelX * the pixel X coordinate that should be converted. @@ -178,7 +186,8 @@ public final class MercatorProjection { } /** - * Converts a pixel Y coordinate at a certain zoom level to a latitude coordinate. + * Converts a pixel Y coordinate at a certain zoom level to a latitude + * coordinate. * * @param pixelY * the pixel Y coordinate that should be converted. @@ -206,7 +215,8 @@ public final class MercatorProjection { } /** - * Converts a tile X number at a certain zoom level to a longitude coordinate. + * Converts a tile X number at a certain zoom level to a longitude + * coordinate. * * @param tileX * the tile X number that should be converted. @@ -219,7 +229,8 @@ public final class MercatorProjection { } /** - * Converts a tile Y number at a certain zoom level to a latitude coordinate. + * Converts a tile Y number at a certain zoom level to a latitude + * coordinate. * * @param tileY * the tile Y number that should be converted. diff --git a/src/org/oscim/utils/FastMath.java b/src/org/oscim/utils/FastMath.java new file mode 100644 index 00000000..ae46db64 --- /dev/null +++ b/src/org/oscim/utils/FastMath.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012 Hannes Janetzek + * + * 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.utils; + +public class FastMath { + /** + * from http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog + * + * @param v + * ... + * @return ... + */ + public static int log2(int v) { + + int r = 0; // result of log2(v) will go here + + if ((v & 0xFFFF0000) != 0) { + v >>= 16; + r |= 16; + } + if ((v & 0xFF00) != 0) { + v >>= 8; + r |= 8; + } + if ((v & 0xF0) != 0) { + v >>= 4; + r |= 4; + } + if ((v & 0xC) != 0) { + v >>= 2; + r |= 2; + } + if ((v & 0x2) != 0) { + r |= 1; + } + return r; + } +} diff --git a/src/org/oscim/view/DelayedTaskHandler.java b/src/org/oscim/view/DelayedTaskHandler.java new file mode 100644 index 00000000..a25d7b79 --- /dev/null +++ b/src/org/oscim/view/DelayedTaskHandler.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012 Hannes Janetzek + * + * 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.view; + +import android.os.Handler; +import android.os.Message; + +public class DelayedTaskHandler extends Handler { + public final int MESSAGE_UPDATE_POSITION = 1; + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MESSAGE_UPDATE_POSITION: + + break; + + } + } +} diff --git a/src/org/oscim/view/MapView.java b/src/org/oscim/view/MapView.java index 2de20e42..3b962745 100644 --- a/src/org/oscim/view/MapView.java +++ b/src/org/oscim/view/MapView.java @@ -83,6 +83,8 @@ public class MapView extends FrameLayout { private String mRenderTheme; private Map mMapOptions; + // private final Handler mHandler; + /** * @param context * the enclosing MapActivity instance. @@ -124,6 +126,8 @@ public class MapView extends FrameLayout { MapActivity mapActivity = (MapActivity) context; + // mHandler = new DelayedTaskHandler(); + debugSettings = new DebugSettings(false, false, false, false); mMapDatabaseType = mapDatabaseType; @@ -205,6 +209,29 @@ public class MapView extends FrameLayout { return mMapViewPosition; } + public void enableRotation(boolean enable) { + enableRotation = enable; + + if (enable) { + enableCompass(false); + } + } + + public void enableCompass(boolean enable) { + if (enable == this.enableCompass) + return; + + this.enableCompass = enable; + + if (enable) + enableRotation(false); + + if (enable) + mCompass.enable(); + else + mCompass.disable(); + } + @Override public boolean onTouchEvent(MotionEvent motionEvent) { // mMapZoomControls.onMapViewTouchEvent(motionEvent.getAction() @@ -601,30 +628,6 @@ public class MapView extends FrameLayout { mapWorker.proceed(); } - public void enableRotation(boolean enable) { - enableRotation = enable; - - if (enable) { - enableCompass(false); - } - } - - public void enableCompass(boolean enable) { - if (enable == this.enableCompass) - return; - - this.enableCompass = enable; - - if (enable) - enableRotation(false); - - if (enable) - mCompass.enable(); - else - mCompass.disable(); - - } - // /** // * Sets the visibility of the zoom controls. // * @@ -647,18 +650,4 @@ public class MapView extends FrameLayout { // mJobParameters = new JobParameters(mJobParameters.theme, textScale); // clearAndRedrawMapView(); // } - - // public final int - // public Handler messageHandler = new Handler() { - // - // @Override - // public void handleMessage(Message msg) { - // switch (msg.what) { - // // handle update - // // ..... - // } - // } - // - // }; - } diff --git a/src/org/oscim/view/MapViewPosition.java b/src/org/oscim/view/MapViewPosition.java index 241b41a0..4a3086a2 100644 --- a/src/org/oscim/view/MapViewPosition.java +++ b/src/org/oscim/view/MapViewPosition.java @@ -17,25 +17,35 @@ package org.oscim.view; import org.oscim.core.GeoPoint; import org.oscim.core.MapPosition; import org.oscim.core.MercatorProjection; - -import android.util.FloatMath; +import org.oscim.utils.FastMath; /** - * A MapPosition stores the latitude and longitude coordinate of a MapView together with its zoom level. + * A MapPosition stores the latitude and longitude coordinate of a MapView + * together with its zoom level. */ public class MapViewPosition { - private static float MAX_SCALE = 2.0f; - private static float MIN_SCALE = 1.0f; - public static int MAX_ZOOMLEVEL = 16; + private static final String TAG = "MapViewPosition"; + + public final static int MAX_ZOOMLEVEL = 16; + + private final static float MAX_SCALE = 2.0f; + private final static float MIN_SCALE = 1.0f; + + private final MapView mMapView; private double mLatitude; private double mLongitude; - private final MapView mMapView; private byte mZoomLevel; private float mScale; private float mRotation; private float mTilt; + // 2^mZoomLevel * mScale; + private float mMapScale; + + // private final static float MAP_SIZE = 1000000; + // private final static float MAP_SIZE2 = 1000000 >> 1; + MapViewPosition(MapView mapView) { mMapView = mapView; @@ -45,8 +55,24 @@ public class MapViewPosition { mScale = 1; mRotation = 0.0f; mTilt = 0; + mMapScale = 1; } + // private static double latitudeToMapView(double latitude) { + // double sinLatitude = Math.sin(latitude * (Math.PI / 180)); + // return (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * + // Math.PI)) + // * MAP_SIZE; + // } + // + // public static double longitudeToMapView(double longitude) { + // return (longitude + 180) / 360 * MAP_SIZE; + // } + // + // private static double pixelXToLongitude(double pixelX, byte zoomLevel) { + // return 360 * ((pixelX / ((long) Tile.TILE_SIZE << zoomLevel)) - 0.5); + // } + /** * @return the current center point of the MapView. */ @@ -55,14 +81,16 @@ public class MapViewPosition { } /** - * @return an immutable MapPosition or null, if this map position is not valid. + * @return an immutable MapPosition or null, if this map position is not + * valid. * @see #isValid() */ public synchronized MapPosition getMapPosition() { if (!isValid()) { return null; } - // Log.d("MapViewPosition", "lat: " + mLatitude + " lon: " + mLongitude); + // Log.d("MapViewPosition", "lat: " + mLatitude + " lon: " + + // mLongitude); return new MapPosition(mLatitude, mLongitude, mZoomLevel, mScale, mRotation); } @@ -178,7 +206,8 @@ public class MapViewPosition { public synchronized void rotateMap(float angle, float cx, float cy) { moveMap(cx, cy); - // Log.d("MapViewPosition", "rotate:" + angle + " " + (mRotation - angle)); + // Log.d("MapViewPosition", "rotate:" + angle + " " + (mRotation - + // angle)); mRotation -= angle; } @@ -186,7 +215,7 @@ public class MapViewPosition { mRotation = f; } - public void setTile(float f) { + public void setTilt(float f) { mTilt = f; } @@ -199,10 +228,12 @@ public class MapViewPosition { mLatitude = MercatorProjection.limitLatitude(mapPosition.lat); mLongitude = MercatorProjection.limitLongitude(mapPosition.lon); mZoomLevel = mMapView.limitZoomLevel(mapPosition.zoomLevel); + mMapScale = 1 << mZoomLevel; } synchronized void setZoomLevel(byte zoomLevel) { mZoomLevel = mMapView.limitZoomLevel(zoomLevel); + mMapScale = 1 << mZoomLevel; } synchronized void setScale(float scale) { @@ -226,79 +257,25 @@ public class MapViewPosition { moveMap(pivotX * (1.0f - scale), pivotY * (1.0f - scale)); - float s = mScale * scale; + float newScale = mMapScale * scale; - if (s >= MAX_SCALE) { - if (s > 8) + int z = FastMath.log2((int) newScale); + + if (z <= 0 || (z >= MAX_ZOOMLEVEL && mScale >= 8)) + return; + + if (z > MAX_ZOOMLEVEL) { + // z16 shows everything, just increase scaling + if (mScale * scale > 8) return; - if (mZoomLevel <= MAX_ZOOMLEVEL) { - byte z = (byte) FloatMath.sqrt(s); - mZoomLevel += z; - s *= 1.0f / (1 << z); - } - } else if (s < MIN_SCALE) { - byte z = (byte) FloatMath.sqrt(1 / s); - if (z != 0 && mZoomLevel == 1) - return; - mZoomLevel -= z; - s *= 1 << z; + mScale *= scale; + mMapScale = newScale; + return; } - mScale = s; + mZoomLevel = (byte) z; + mScale = newScale / (1 << z); + mMapScale = newScale; } - - /** - * Zooms in or out by the given amount of zoom levels. - * - * @param zoomLevelDiff - * the difference to the current zoom level. - * @param s - * scale between min/max zoom - * @return true if the zoom level was changed, false otherwise. - */ - // public boolean zoom(byte zoomLevelDiff, float s) { - // float scale = s; - // - // if (zoomLevelDiff > 0) { - // // check if zoom in is possible - // if (mMapViewPosition.getZoomLevel() + zoomLevelDiff > getMaximumPossibleZoomLevel()) { - // return false; - // } - // - // scale *= 1.0f / (1 << zoomLevelDiff); - // } else if (zoomLevelDiff < 0) { - // // check if zoom out is possible - // if (mMapViewPosition.getZoomLevel() + zoomLevelDiff < mMapZoomControls.getZoomLevelMin()) { - // return false; - // } - // - // scale *= 1 << -zoomLevelDiff; - // } - // - // if (scale == 0) - // scale = 1; - // // else - // // scale = Math.round(256.0f * scale) / 256.0f; - // - // mMapViewPosition.setZoomLevel((byte) (mMapViewPosition.getZoomLevel() + zoomLevelDiff)); - // - // // mapZoomControls.onZoomLevelChange(mapViewPosition.getZoomLevel()); - // - // // zoomAnimator.setParameters(zoomStart, matrixScaleFactor, - // // getWidth() >> 1, getHeight() >> 1); - // // zoomAnimator.startAnimation(); - // - // // if (scale > MAX_ZOOM) { - // // scale = MAX_ZOOM; - // // } - // - // if (zoomLevelDiff != 0 || mZoomFactor != scale) { - // mZoomFactor = scale; - // redrawTiles(); - // } - // - // return true; - // } - } diff --git a/src/org/oscim/view/TouchHandler.java b/src/org/oscim/view/TouchHandler.java index 7915789b..a44a8e3a 100644 --- a/src/org/oscim/view/TouchHandler.java +++ b/src/org/oscim/view/TouchHandler.java @@ -29,7 +29,8 @@ import android.view.animation.DecelerateInterpolator; import android.widget.Scroller; /** - * Implementation for multi-touch capable devices. TODO write a AnimationTimer instead of using CountDownTimer + * Implementation for multi-touch capable devices. TODO write a AnimationTimer + * instead of using CountDownTimer */ public class TouchHandler { private static final int INVALID_POINTER_ID = -1; @@ -440,7 +441,8 @@ public class TouchHandler { @Override public void onScaleEnd(ScaleGestureDetector gd) { - // Log.d("ScaleListener", "Sum " + mSumScale + " " + (mTimeEnd - mTimeStart)); + // Log.d("ScaleListener", "Sum " + mSumScale + " " + (mTimeEnd - + // mTimeStart)); if (mTimer == null && mTimeEnd - mTimeStart < 150 && (mSumScale < 0.99 || mSumScale > 1.01)) { @@ -449,7 +451,7 @@ public class TouchHandler { mZooutOut = mSumScale < 0.99; - mTimer = new CountDownTimer((int) mScaleDuration, 30) { + mTimer = new CountDownTimer((int) mScaleDuration, 15) { @Override public void onTick(long tick) { scale(tick); @@ -468,7 +470,7 @@ public class TouchHandler { private float mPrevScale; private CountDownTimer mTimer; boolean mZooutOut; - private final float mScaleDuration = 350; + private final float mScaleDuration = 450; boolean scale(long tick) { diff --git a/src/org/oscim/view/overlay/Overlay.java b/src/org/oscim/view/overlay/Overlay.java index 23aeb6db..4d5a2a04 100644 --- a/src/org/oscim/view/overlay/Overlay.java +++ b/src/org/oscim/view/overlay/Overlay.java @@ -1,5 +1,5 @@ /* - * Copyright 2010, 2011, 2012 mapsforge.org + * Copyright 2012, Hannes Janetzek * * 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 diff --git a/src/org/oscim/view/renderer/GLRenderer.java b/src/org/oscim/view/renderer/GLRenderer.java index 04e769c7..2463fef1 100644 --- a/src/org/oscim/view/renderer/GLRenderer.java +++ b/src/org/oscim/view/renderer/GLRenderer.java @@ -16,19 +16,12 @@ package org.oscim.view.renderer; import static android.opengl.GLES20.GL_ARRAY_BUFFER; import static android.opengl.GLES20.GL_BLEND; +import static android.opengl.GLES20.GL_DEPTH_TEST; import static android.opengl.GLES20.GL_DYNAMIC_DRAW; +import static android.opengl.GLES20.GL_ONE; import static android.opengl.GLES20.GL_ONE_MINUS_SRC_ALPHA; +import static android.opengl.GLES20.GL_POLYGON_OFFSET_FILL; import static android.opengl.GLES20.GL_STENCIL_BUFFER_BIT; -import static android.opengl.GLES20.glBindBuffer; -import static android.opengl.GLES20.glBlendFunc; -import static android.opengl.GLES20.glBufferData; -import static android.opengl.GLES20.glClear; -import static android.opengl.GLES20.glClearColor; -import static android.opengl.GLES20.glClearStencil; -import static android.opengl.GLES20.glDisable; -import static android.opengl.GLES20.glEnable; -import static android.opengl.GLES20.glGenBuffers; -import static android.opengl.GLES20.glViewport; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -69,7 +62,6 @@ public class GLRenderer implements GLSurfaceView.Renderer { private static ArrayList mVBOs; private static int mWidth, mHeight; - private static float mAspect; private static int rotateBuffers = 2; private static ShortBuffer shortBuffer[]; @@ -86,12 +78,12 @@ public class GLRenderer implements GLSurfaceView.Renderer { private static float[] mProjMatrix = new float[16]; private static float[] mProjMatrixI = new float[16]; - // curTiles is set by TileLoader and swapped with - // drawTiles in onDrawFrame in GL thread. - private static TilesData curTiles, drawTiles; + // mNextTiles is set by TileLoader and swapped with + // mDrawTiles in onDrawFrame in GL thread. + private static TilesData mNextTiles, mDrawTiles; // flag set by updateVisibleList when current visible tiles - // changed. used in onDrawFrame to flip curTiles/drawTiles + // changed. used in onDrawFrame to flip mNextTiles/mDrawTiles private static boolean mUpdateTiles; private static MapPosition mCurPosition; @@ -147,7 +139,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { * current MapPosition * @param tiles * active tiles - * @return curTiles (the previously active tiles) + * @return mNextTiles (the previously active tiles) */ static TilesData updateTiles(MapPosition mapPosition, TilesData tiles) { GLRenderer.tilelock.lock(); @@ -155,8 +147,8 @@ public class GLRenderer implements GLSurfaceView.Renderer { mCurPosition = mapPosition; // unlock previously active tiles - for (int i = 0; i < curTiles.cnt; i++) { - MapTile t = curTiles.tiles[i]; + for (int i = 0; i < mNextTiles.cnt; i++) { + MapTile t = mNextTiles.tiles[i]; boolean found = false; for (int j = 0; j < tiles.cnt; j++) { @@ -168,8 +160,8 @@ public class GLRenderer implements GLSurfaceView.Renderer { if (found) continue; - for (int j = 0; j < drawTiles.cnt; j++) { - if (drawTiles.tiles[j] == t) { + for (int j = 0; j < mDrawTiles.cnt; j++) { + if (mDrawTiles.tiles[j] == t) { found = true; break; } @@ -180,22 +172,23 @@ public class GLRenderer implements GLSurfaceView.Renderer { t.unlock(); } - TilesData tmp = curTiles; - curTiles = tiles; + TilesData tmp = mNextTiles; + mNextTiles = tiles; // lock tiles (and their proxies) to not be removed from cache - for (int i = 0; i < curTiles.cnt; i++) { - MapTile t = curTiles.tiles[i]; + for (int i = 0; i < mNextTiles.cnt; i++) { + MapTile t = mNextTiles.tiles[i]; if (!t.isActive) t.lock(); } - for (int j = 0; j < drawTiles.cnt; j++) { - MapTile t = drawTiles.tiles[j]; + for (int j = 0; j < mDrawTiles.cnt; j++) { + MapTile t = mDrawTiles.tiles[j]; if (!t.isActive) t.lock(); } + // GLThread flips mNextTiles with mDrawTiles mUpdateTiles = true; GLRenderer.tilelock.unlock(); @@ -236,46 +229,6 @@ public class GLRenderer implements GLSurfaceView.Renderer { mUpdateColor = true; } - private static boolean isVisible(MapPosition mapPosition, MapTile tile, float div) { - double dx, dy, scale; - - if (div == 0) { - dx = tile.pixelX - mapPosition.x; - dy = tile.pixelY - mapPosition.y; - scale = mapPosition.scale; - } else { - dx = tile.pixelX - mapPosition.x * div; - dy = tile.pixelY - mapPosition.y * div; - scale = mapPosition.scale / div; - } - int size = Tile.TILE_SIZE; - int sx = (int) (dx * scale); - int sy = (int) (dy * scale); - - // FIXME little hack, need to do scanline check or sth - // this kindof works for typical screen aspect - if (mRotate) { - int ssize = mWidth > mHeight ? mWidth : mHeight; - - if (sy > ssize / 2 || sx > ssize / 2 - || sx + size * scale < -ssize / 2 - || sy + size * scale < -ssize / 2) { - tile.isVisible = false; - return false; - } - } else { - if (sy > mHeight / 2 || sx > mWidth / 2 - || sx + size * scale < -mWidth / 2 - || sy + size * scale < -mHeight / 2) { - tile.isVisible = false; - return false; - } - } - tile.isVisible = true; - - return true; - } - private int uploadCnt = 0; private boolean uploadTileData(MapTile tile) { @@ -308,7 +261,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { } // Log.d(TAG, "uploadTileData, " + tile); - glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id); + GLES20.glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id); sbuf = shortBuffer[uploadCnt]; @@ -317,8 +270,8 @@ public class GLRenderer implements GLSurfaceView.Renderer { // FIXME probably not a good idea to do this in gl thread... if (sbuf == null || sbuf.capacity() < newSize) { - ByteBuffer bbuf = ByteBuffer.allocateDirect(newSize * SHORT_BYTES).order( - ByteOrder.nativeOrder()); + ByteBuffer bbuf = ByteBuffer.allocateDirect(newSize * SHORT_BYTES) + .order(ByteOrder.nativeOrder()); sbuf = bbuf.asShortBuffer(); shortBuffer[uploadCnt] = sbuf; sbuf.put(mFillCoords, 0, 8); @@ -346,7 +299,6 @@ public class GLRenderer implements GLSurfaceView.Renderer { sbuf.flip(); if (newSize != sbuf.remaining()) { - Log.d(TAG, "tiles wrong: " + tile + " " + newSize + " " + sbuf.position() + " " @@ -361,13 +313,16 @@ public class GLRenderer implements GLSurfaceView.Renderer { } newSize *= SHORT_BYTES; + // reuse memory allocated for vbo when possible and allocated + // memory is less then four times the new data if (tile.vbo.size > newSize && tile.vbo.size < newSize * 4 && mBufferMemoryUsage < LIMIT_BUFFERS) { GLES20.glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, sbuf); + // Log.d(TAG, "reuse buffer " + tile.vbo.size + " " + newSize); } else { mBufferMemoryUsage -= tile.vbo.size; tile.vbo.size = newSize; - glBufferData(GL_ARRAY_BUFFER, tile.vbo.size, sbuf, GL_DYNAMIC_DRAW); + GLES20.glBufferData(GL_ARRAY_BUFFER, tile.vbo.size, sbuf, GL_DYNAMIC_DRAW); mBufferMemoryUsage += tile.vbo.size; } @@ -380,47 +335,96 @@ public class GLRenderer implements GLSurfaceView.Renderer { } private static void checkBufferUsage() { - // try to clear some unused vbo when exceding limit - if (mBufferMemoryUsage > LIMIT_BUFFERS) { - Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / MB + "MB"); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - int buf[] = new int[1]; - - synchronized (mVBOs) { - for (VertexBufferObject vbo : mVBOs) { - - if (vbo.size == 0) - continue; - - mBufferMemoryUsage -= vbo.size; - - // this should free allocated memory but it does not. - // on HTC it causes oom exception?! - - // glBindBuffer(GL_ARRAY_BUFFER, vbo.id); - // glBufferData(GL_ARRAY_BUFFER, 0, null, - // GLES20.GL_STATIC_DRAW); - - // recreate vbo instead - buf[0] = vbo.id; - GLES20.glDeleteBuffers(1, buf, 0); - GLES20.glGenBuffers(1, buf, 0); - vbo.id = buf[0]; - - vbo.size = 0; - } - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - Log.d(TAG, " > " + mBufferMemoryUsage / MB + "MB"); - - if (mBufferMemoryUsage > LIMIT_BUFFERS && CACHE_TILES > 100) - CACHE_TILES -= 50; - - } else if (CACHE_TILES < CACHE_TILES_MAX) { - CACHE_TILES += 50; + if (mBufferMemoryUsage < LIMIT_BUFFERS) { + if (CACHE_TILES < CACHE_TILES_MAX) + CACHE_TILES += 50; + return; } + + // try to clear some unused vbo when exceding limit + Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / MB + "MB"); + + int vboIds[] = new int[10]; + VertexBufferObject[] tmp = new VertexBufferObject[10]; + + int removed = 0; + synchronized (mVBOs) { + for (VertexBufferObject vbo : mVBOs) { + + if (vbo.size == 0) + continue; + + mBufferMemoryUsage -= vbo.size; + vbo.size = 0; + + // this should free allocated memory but it does not. + // on HTC it causes OOM exception?! + // glBindBuffer(GL_ARRAY_BUFFER, vbo.id); + // glBufferData(GL_ARRAY_BUFFER, 0, null, + // GLES20.GL_STATIC_DRAW); + + // recreate vbo instead + vboIds[removed] = vbo.id; + tmp[removed++] = vbo; + + if (removed == 10) + break; + } + } + + if (removed > 0) { + GLES20.glDeleteBuffers(removed, vboIds, 0); + GLES20.glGenBuffers(removed, vboIds, 0); + + for (int i = 0; i < removed; i++) + tmp[i].id = vboIds[i]; + + Log.d(TAG, "now: " + mBufferMemoryUsage / MB + "MB"); + } + + if (mBufferMemoryUsage > LIMIT_BUFFERS && CACHE_TILES > 100) + CACHE_TILES -= 50; + } + + private static boolean isVisible(MapPosition mapPosition, MapTile tile) { + float dx, dy, scale, div = 1; + int diff = mapPosition.zoomLevel - tile.zoomLevel; + + if (diff < 0) + div = (1 << -diff); + else if (diff > 0) + div = (1.0f / (1 << diff)); + + scale = mapPosition.scale / div; + dx = (float) (tile.pixelX - mapPosition.x * div); + dy = (float) (tile.pixelY - mapPosition.y * div); + + int size = Tile.TILE_SIZE; + int sx = (int) (dx * scale); + int sy = (int) (dy * scale); + + // FIXME little hack, need to do scanline check or sth + // this kindof works for typical screen aspect + if (mRotate) { + int ssize = mWidth > mHeight ? mWidth : mHeight; + + if (sy > ssize / 2 || sx > ssize / 2 + || sx + size * scale < -ssize / 2 + || sy + size * scale < -ssize / 2) { + tile.isVisible = false; + return false; + } + } else { + if (sy > mHeight / 2 || sx > mWidth / 2 + || sx + size * scale < -mWidth / 2 + || sy + size * scale < -mHeight / 2) { + tile.isVisible = false; + return false; + } + } + tile.isVisible = true; + + return true; } private static boolean mRotate = false; @@ -429,17 +433,16 @@ public class GLRenderer implements GLSurfaceView.Renderer { float div, boolean project) { float x, y, scale; - // if (mRotate) { scale = mapPosition.scale / (div * COORD_MULTIPLIER); x = (float) (tile.pixelX - mapPosition.x * div); y = (float) (tile.pixelY - mapPosition.y * div); Matrix.setIdentityM(matrix, 0); - // scale to tile coordinates + // scale to tile to world coordinates Matrix.scaleM(matrix, 0, scale, scale, 1); - // translate relative to center + // translate relative to map center Matrix.translateM(matrix, 0, x * COORD_MULTIPLIER, -(y + Tile.TILE_SIZE) * COORD_MULTIPLIER, @@ -450,44 +453,31 @@ public class GLRenderer implements GLSurfaceView.Renderer { if (project) Matrix.multiplyMM(matrix, 0, mProjMatrix, 0, matrix, 0); - - // } else { - // scale = (float) (2.0 * mapPosition.scale / (mHeight * div)); - // x = (float) (tile.pixelX - mapPosition.x * div); - // y = (float) (tile.pixelY - mapPosition.y * div); - // - // matrix[12] = x * scale * mAspect; - // matrix[13] = -(y + Tile.TILE_SIZE) * scale; - // // increase the 'distance' with each tile drawn. - // matrix[14] = -0.99f + offset * 0.01f; - // matrix[0] = scale * mAspect / COORD_MULTIPLIER; - // matrix[5] = scale / COORD_MULTIPLIER; - // } } - private float[] mv = new float[4]; - private float[] mu = { 1, 1, -1, 1 }; - - private float[] mUnprojMatrix = new float[16]; - - private void unproject(MapPosition pos, float x, float y) { - mu[0] = x; - mu[1] = y; - mu[2] = -1; - - // add tilt - Matrix.multiplyMV(mv, 0, mTmpMatrix, 0, mu, 0); - // Log.d(TAG, ">> " + mv[0] + " " + mv[1] + " " + mv[2]); - - Matrix.multiplyMV(mv, 0, mUnprojMatrix, 0, mv, 0); - float size = Tile.TILE_SIZE * pos.scale; - if (mv[3] != 0) { - float w = 1 / mv[3]; - float xx = Math.round(((mv[0] * w) / size) * 100) / 100f; - float yy = Math.round(((mv[1] * w) / size) * 100) / 100f; - Log.d(TAG, " " + xx + " " + yy); - } - } + // private float[] mv = new float[4]; + // private float[] mu = { 1, 1, -1, 1 }; + // + // private float[] mUnprojMatrix = new float[16]; + // + // private void unproject(MapPosition pos, float x, float y) { + // mu[0] = x; + // mu[1] = y; + // mu[2] = -1; + // + // // add tilt + // Matrix.multiplyMV(mv, 0, mTmpMatrix, 0, mu, 0); + // // Log.d(TAG, ">> " + mv[0] + " " + mv[1] + " " + mv[2]); + // + // Matrix.multiplyMV(mv, 0, mUnprojMatrix, 0, mv, 0); + // float size = Tile.TILE_SIZE * pos.scale; + // if (mv[3] != 0) { + // float w = 1 / mv[3]; + // float xx = Math.round(((mv[0] * w) / size) * 100) / 100f; + // float yy = Math.round(((mv[1] * w) / size) * 100) / 100f; + // Log.d(TAG, " " + xx + " " + yy); + // } + // } @Override public void onDrawFrame(GL10 glUnused) { @@ -498,30 +488,27 @@ public class GLRenderer implements GLSurfaceView.Renderer { if (MapView.debugFrameTime) start = SystemClock.uptimeMillis(); + // Note: it seems faster to also clear the stencil buffer even + // when not needed. probaly otherwise it is masked out from the + // depth buffer as they share the same memory region afaik GLES20.glDepthMask(true); - - // Note: having the impression it is faster to also clear the - // stencil buffer even when not needed. probaly otherwise it - // is masked out from the depth buffer as they share the same - // memory region afaik - glClear(GLES20.GL_COLOR_BUFFER_BIT + GLES20.glStencilMask(0xFF); + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT - // | GLES20.GL_STENCIL_BUFFER_BIT - ); + | GLES20.GL_STENCIL_BUFFER_BIT); // get position and current tiles to draw GLRenderer.tilelock.lock(); mapPosition = mCurPosition; - if (mUpdateTiles) { - TilesData tmp = drawTiles; - drawTiles = curTiles; - curTiles = tmp; + TilesData tmp = mDrawTiles; + mDrawTiles = mNextTiles; + mNextTiles = tmp; mUpdateTiles = false; } GLRenderer.tilelock.unlock(); - if (drawTiles == null) + if (mDrawTiles == null) return; // if (mRotate != (mMapView.enableRotation || mMapView.enableCompass)) { @@ -572,12 +559,13 @@ public class GLRenderer implements GLSurfaceView.Renderer { } if (mUpdateColor && mClearColor != null) { - glClearColor(mClearColor[0], mClearColor[1], mClearColor[2], mClearColor[3]); + GLES20.glClearColor(mClearColor[0], mClearColor[1], mClearColor[2], + mClearColor[3]); mUpdateColor = false; } - int tileCnt = drawTiles.cnt; - MapTile[] tiles = drawTiles.tiles; + int tileCnt = mDrawTiles.cnt; + MapTile[] tiles = mDrawTiles.tiles; uploadCnt = 0; int updateTextures = 0; @@ -586,7 +574,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { for (int i = 0; i < tileCnt; i++) { MapTile tile = tiles[i]; - if (!isVisible(mapPosition, tile, 1)) + if (!isVisible(mapPosition, tile)) continue; if (tile.texture == null && TextRenderer.drawToTexture(tile)) @@ -621,32 +609,29 @@ public class GLRenderer implements GLSurfaceView.Renderer { if (updateTextures > 0) TextRenderer.compileTextures(); - GLES20.glEnable(GLES20.GL_DEPTH_TEST); - GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL); + GLES20.glEnable(GL_DEPTH_TEST); + GLES20.glEnable(GL_POLYGON_OFFSET_FILL); for (int i = 0; i < tileCnt; i++) { - if (tiles[i].isVisible && tiles[i].isReady) { - drawTile(mapPosition, tiles[i], 1); - } + if (tiles[i].isVisible && tiles[i].isReady) + drawTile(mapPosition, tiles[i]); } // proxies are clipped to the region where nothing was drawn to depth - // buffer - // TODO draw all parent before grandparent + // buffer. TODO draw all parent before grandparent for (int i = 0; i < tileCnt; i++) { - if (tiles[i].isVisible && !tiles[i].isReady) { + if (tiles[i].isVisible && !tiles[i].isReady) drawProxyTile(mapPosition, tiles[i]); - } } // GlUtils.checkGlError("end draw"); - GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL); - GLES20.glDisable(GLES20.GL_DEPTH_TEST); + GLES20.glDisable(GL_POLYGON_OFFSET_FILL); + GLES20.glDisable(GL_DEPTH_TEST); mDrawCount = 0; mDrawSerial++; - glEnable(GL_BLEND); + GLES20.glEnable(GL_BLEND); int z = mapPosition.zoomLevel; float s = mapPosition.scale; @@ -683,11 +668,20 @@ public class GLRenderer implements GLSurfaceView.Renderer { // used to not draw a tile twice per frame... private static byte mDrawSerial = 0; - private static void drawTile(MapPosition mapPosition, MapTile tile, float div) { + private static void drawTile(MapPosition mapPosition, MapTile tile) { // draw parents only once if (tile.lastDraw == mDrawSerial) return; + float div = 1; + + int diff = mapPosition.zoomLevel - tile.zoomLevel; + + if (diff < 0) + div = (1 << -diff); + else if (diff > 0) + div = (1.0f / (1 << diff)); + tile.lastDraw = mDrawSerial; int z = mapPosition.zoomLevel; @@ -698,7 +692,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { GLES20.glPolygonOffset(0, mDrawCount++); - glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id); + GLES20.glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id); LineLayer ll = tile.lineLayers; PolygonLayer pl = tile.polygonLayers; @@ -716,10 +710,9 @@ public class GLRenderer implements GLSurfaceView.Renderer { pnext = pl.layer; if (pl != null && pnext < lnext) { - glDisable(GL_BLEND); + GLES20.glDisable(GL_BLEND); - pl = PolygonRenderer.drawPolygons(pl, lnext, mvp, z, s, - !clipped); + pl = PolygonRenderer.drawPolygons(pl, lnext, mvp, z, s, !clipped); clipped = true; @@ -730,7 +723,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { clipped = true; } - glEnable(GL_BLEND); + GLES20.glEnable(GL_BLEND); ll = LineRenderer.drawLines(tile, ll, pnext, mvp, div, z, s); } } @@ -747,13 +740,13 @@ public class GLRenderer implements GLSurfaceView.Renderer { if (c == null) continue; - if (!isVisible(mapPosition, c, 2)) { + if (!isVisible(mapPosition, c)) { drawn++; continue; } if (c.isReady) { - drawTile(mapPosition, c, 2); + drawTile(mapPosition, c); drawn++; } } @@ -762,36 +755,38 @@ public class GLRenderer implements GLSurfaceView.Renderer { // TODO could use tile.proxies here private static void drawProxyTile(MapPosition mapPosition, MapTile tile) { - + boolean drawn = false; if (mapPosition.scale > 1.5f) { // prefer drawing children if (!drawProxyChild(mapPosition, tile)) { - MapTile t = tile.rel.parent.tile; - if (t != null) { + if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { + MapTile t = tile.rel.parent.tile; if (t.isReady) { - drawTile(mapPosition, t, 0.5f); - } else { - MapTile p = t.rel.parent.tile; - if (p != null && p.isReady) - drawTile(mapPosition, p, 0.25f); + drawTile(mapPosition, t); + drawn = true; } } + + if (!drawn && (tile.proxies & MapTile.PROXY_GRAMPA) != 0) { + MapTile t = tile.rel.parent.parent.tile; + if (t.isReady) + drawTile(mapPosition, t); + + } } } else { // prefer drawing parent MapTile t = tile.rel.parent.tile; if (t != null && t.isReady) { - drawTile(mapPosition, t, 0.5f); + drawTile(mapPosition, t); } else if (!drawProxyChild(mapPosition, tile)) { - // need to check rel.parent here, t could alread be root - if (t != null) { - t = t.rel.parent.tile; - - if (t != null && t.isReady) - drawTile(mapPosition, t, 0.25f); + if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) { + t = tile.rel.parent.parent.tile; + if (t.isReady) + drawTile(mapPosition, t); } } } @@ -811,8 +806,6 @@ public class GLRenderer implements GLSurfaceView.Renderer { mWidth = width; mHeight = height; - mAspect = (float) height / width; - // Matrix.orthoM(mProjMatrix, 0, -0.5f / mAspect, 0.5f / mAspect, -0.5f, // 0.5f, -1, 1); @@ -828,7 +821,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { mProjMatrix[10] = 0; mProjMatrix[14] = 0; - glViewport(0, 0, width, height); + GLES20.glViewport(0, 0, width, height); if (!changed && !mNewSurface) { mMapView.redrawMap(); @@ -845,7 +838,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { // Set up vertex buffer objects int numVBO = (CACHE_TILES + (numTiles * 2)); int[] mVboIds = new int[numVBO]; - glGenBuffers(numVBO, mVboIds, 0); + GLES20.glGenBuffers(numVBO, mVboIds, 0); GlUtils.checkGlError("glGenBuffers"); mVBOs = new ArrayList(numVBO); @@ -857,22 +850,22 @@ public class GLRenderer implements GLSurfaceView.Renderer { TextRenderer.setup(numTiles); if (mClearColor != null) { - glClearColor(mClearColor[0], mClearColor[1], + GLES20.glClearColor(mClearColor[0], mClearColor[1], mClearColor[2], mClearColor[3]); } else { - glClearColor(0.98f, 0.98f, 0.97f, 1.0f); + GLES20.glClearColor(0.98f, 0.98f, 0.97f, 1.0f); } GlUtils.checkGlError("onSurfaceChanged"); - glClear(GL_STENCIL_BUFFER_BIT); + GLES20.glClear(GL_STENCIL_BUFFER_BIT); mMapView.redrawMap(); } void clearTiles(int numTiles) { - drawTiles = new TilesData(numTiles); - curTiles = new TilesData(numTiles); + mDrawTiles = new TilesData(numTiles); + mNextTiles = new TilesData(numTiles); } @Override @@ -904,9 +897,9 @@ public class GLRenderer implements GLSurfaceView.Renderer { // glEnable(GL_SCISSOR_TEST); // glScissor(0, 0, mWidth, mHeight); - glClearStencil(0); - glDisable(GLES20.GL_CULL_FACE); - glBlendFunc(GLES20.GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + GLES20.glClearStencil(0); + GLES20.glDisable(GLES20.GL_CULL_FACE); + GLES20.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } diff --git a/src/org/oscim/view/renderer/LineLayer.java b/src/org/oscim/view/renderer/LineLayer.java index de4835ee..b935dff4 100644 --- a/src/org/oscim/view/renderer/LineLayer.java +++ b/src/org/oscim/view/renderer/LineLayer.java @@ -25,7 +25,8 @@ class LineLayer { private static final float COORD_SCALE = GLRenderer.COORD_MULTIPLIER; // scale factor mapping extrusion vector to short values private static final float DIR_SCALE = 2048; - // mask for packing last two bits of extrusion vector with texture coordinates + // mask for packing last two bits of extrusion vector with texture + // coordinates private static final int DIR_MASK = 0xFFFFFFFC; // next layer @@ -64,7 +65,8 @@ class LineLayer { } /* - * line extrusion is based on code from GLMap (https://github.com/olofsj/GLMap/) by olofsj + * line extrusion is based on code from GLMap + * (https://github.com/olofsj/GLMap/) by olofsj */ void addLine(float[] points, short[] index, boolean closed) { diff --git a/src/org/oscim/view/renderer/LineRenderer.java b/src/org/oscim/view/renderer/LineRenderer.java index ac2373bf..8bcff25d 100644 --- a/src/org/oscim/view/renderer/LineRenderer.java +++ b/src/org/oscim/view/renderer/LineRenderer.java @@ -62,11 +62,10 @@ class LineRenderer { static LineLayer drawLines(MapTile tile, LineLayer layer, int next, float[] matrix, float div, double zoom, float scale) { - float z = 1 / div; - if (layer == null) return null; + // TODO should use fast line program when view is not tilted GLES20.glUseProgram(lineProgram); GLES20.glEnableVertexAttribArray(hLineVertexPosition); @@ -81,7 +80,9 @@ class LineRenderer { GLES20.glUniformMatrix4fv(hLineMatrix, 1, false, matrix, 0); // scale factor to map one pixel on tile to one pixel on screen: - float pixel = 2.0f / (scale * z); + // only works with orthographic projection + float s = scale / div; + float pixel = 2.0f / s; if (mFast) GLES20.glUniform1f(hLineScale, pixel); @@ -89,7 +90,7 @@ class LineRenderer { GLES20.glUniform1f(hLineScale, 0); // line scale factor (for non fixed lines) - float s = FloatMath.sqrt(scale * z); + float lineScale = FloatMath.sqrt(s); boolean blur = false; LineLayer l = layer; @@ -117,33 +118,31 @@ class LineRenderer { for (LineLayer o = l.outlines; o != null; o = o.outlines) { if (line.blur != 0) { - GLES20.glUniform1f(hLineScale, (l.width + o.width) / (scale * z) - - (line.blur / (scale * z))); + GLES20.glUniform1f(hLineScale, (l.width + o.width) / s + - (line.blur / s)); blur = true; } if (zoom > TileGenerator.STROKE_MAX_ZOOM_LEVEL) - GLES20.glUniform1f(hLineWidth, - (l.width + o.width) / (scale * z)); + GLES20.glUniform1f(hLineWidth, (l.width + o.width) / s); else - GLES20.glUniform1f(hLineWidth, l.width / (scale * z) - + o.width / s); + GLES20.glUniform1f(hLineWidth, l.width / s + o.width / lineScale); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, o.offset, o.verticesCnt); } } else { if (line.blur != 0) { - GLES20.glUniform1f(hLineScale, (l.width / s) * line.blur); + GLES20.glUniform1f(hLineScale, (l.width / lineScale) * line.blur); blur = true; } if (line.fixed || zoom > TileGenerator.STROKE_MAX_ZOOM_LEVEL) { // invert scaling of extrusion vectors so that line width - // stays the same - GLES20.glUniform1f(hLineWidth, (l.width / (scale * z))); + // stays the same. + GLES20.glUniform1f(hLineWidth, l.width / s); } else { - GLES20.glUniform1f(hLineWidth, (l.width / s)); + GLES20.glUniform1f(hLineWidth, l.width / lineScale); } GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, l.offset, l.verticesCnt); diff --git a/src/org/oscim/view/renderer/MapRenderer.java b/src/org/oscim/view/renderer/MapRenderer.java index fce9c3db..98a5d47f 100644 --- a/src/org/oscim/view/renderer/MapRenderer.java +++ b/src/org/oscim/view/renderer/MapRenderer.java @@ -91,13 +91,10 @@ public class MapRenderer extends GLSurfaceView { mInitial = true; } - /** - * called by MapView when position or map settings changes - */ /** * Update list of visible tiles and passes them to MapRenderer, when not * available tiles are created and added to JobQueue (mapView.addJobs) for - * loading by MapGenerator class + * loading by TileGenerator class * * @param clear * ... @@ -108,7 +105,7 @@ public class MapRenderer extends GLSurfaceView { boolean changedPos = false; boolean changedZoom = false; - if (mMapView == null || mMapView.getMapPosition() == null) + if (mMapView == null) return; MapPosition mapPosition = mMapView.getMapPosition().getMapPosition(); @@ -121,14 +118,17 @@ public class MapRenderer extends GLSurfaceView { if (clear) { // remove all tiles references Log.d(TAG, "CLEAR"); - synchronized (GLRenderer.lock) { - for (MapTile t : mTiles) - clearTile(t); - mTiles.clear(); - mTilesLoaded.clear(); - QuadTree.init(); - } + GLRenderer.tilelock.lock(); + + for (MapTile t : mTiles) + clearTile(t); + + mTiles.clear(); + mTilesLoaded.clear(); + QuadTree.init(); + GLRenderer.tilelock.unlock(); + mInitial = true; } @@ -180,21 +180,29 @@ public class MapRenderer extends GLSurfaceView { mTileY = tileY; mPrevZoom = zoomLevel; - if (changedZoom) { - // need to update visible list first when zoom level changes - // as scaling is relative to the tiles of current zoom-level - updateVisibleList(mapPosition, 0); - } else { - // pass new position to glThread - GLRenderer.updatePosition(mapPosition); - } - + GLRenderer.updatePosition(mapPosition); if (!MapView.debugFrameTime) requestRender(); - if (changedPos) + if (changedZoom || changedPos) { + // need to update visible list first when zoom level changes + // as scaling is relative to the tiles of current zoom-level updateVisibleList(mapPosition, zdir); + if (!MapView.debugFrameTime) + requestRender(); + } + // else { + // // pass new position to glThread + // GLRenderer.updatePosition(mapPosition); + // } + + // if (!MapView.debugFrameTime) + // requestRender(); + + // if (changedPos) + // updateVisibleList(mapPosition, zdir); + if (changedPos || changedZoom) { int remove = mTiles.size() - GLRenderer.CACHE_TILES; if (remove > 50) @@ -202,7 +210,6 @@ public class MapRenderer extends GLSurfaceView { } limitLoadQueue(); - } /** diff --git a/src/org/oscim/view/renderer/MapTile.java b/src/org/oscim/view/renderer/MapTile.java index faee74e6..b0568b6d 100644 --- a/src/org/oscim/view/renderer/MapTile.java +++ b/src/org/oscim/view/renderer/MapTile.java @@ -19,7 +19,8 @@ import org.oscim.view.generator.JobTile; class MapTile extends JobTile { /** - * VBO layout: - 16 bytes fill coordinates, n bytes polygon vertices, m bytes lines vertices + * VBO layout: - 16 bytes fill coordinates, n bytes polygon vertices, m + * bytes lines vertices */ VertexBufferObject vbo; @@ -65,8 +66,8 @@ class MapTile extends JobTile { byte lastDraw = 0; // keep track which tiles are locked as proxy for this tile - // 16: parent - // 32: grandparent + final static int PROXY_PARENT = 16; + final static int PROXY_GRAMPA = 32; // 1-8: children byte proxies; @@ -99,12 +100,12 @@ class MapTile extends JobTile { MapTile p = rel.parent.tile; if (p != null && (p.isReady || p.newData || p.isLoading)) { - proxies |= (1 << 4); + proxies |= PROXY_PARENT; p.refs++; } else { p = rel.parent.parent.tile; if (p != null && (p.isReady || p.newData || p.isLoading)) { - proxies |= (1 << 5); + proxies |= PROXY_GRAMPA; p.refs++; } } diff --git a/src/org/oscim/view/renderer/PolygonRenderer.java b/src/org/oscim/view/renderer/PolygonRenderer.java index faade673..137e5245 100644 --- a/src/org/oscim/view/renderer/PolygonRenderer.java +++ b/src/org/oscim/view/renderer/PolygonRenderer.java @@ -42,6 +42,8 @@ import org.oscim.utils.GlUtils; import android.opengl.GLES20; class PolygonRenderer { + private static final String TAG = "PolygonRenderer"; + private static final int NUM_VERTEX_SHORTS = 2; private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0; private static int STENCIL_BITS = 8; @@ -71,7 +73,7 @@ class PolygonRenderer { return true; } - private static void fillPolygons(int count, double zoom, float scale) { + private static void fillPolygons(double zoom, float scale) { boolean blend = false; /* draw to framebuffer */ @@ -83,7 +85,7 @@ class PolygonRenderer { /* only draw where nothing was drawn yet */ glEnable(GLES20.GL_DEPTH_TEST); - for (int c = 0; c < count; c++) { + for (int c = mStart; c < mCount; c++) { PolygonLayer l = mFillPolys[c]; float f = 1.0f; @@ -149,8 +151,13 @@ class PolygonRenderer { glDisable(GL_BLEND); } - static PolygonLayer drawPolygons(PolygonLayer layer, int next, - float[] matrix, double zoom, float scale, boolean clip) { + // layers to fill + private static int mCount; + // stencil buffer index to start fill + private static int mStart; + + static PolygonLayer drawPolygons(final PolygonLayer layer, final int next, + final float[] matrix, final double zoom, final float scale, boolean first) { glUseProgram(polygonProgram); GLES20.glEnableVertexAttribArray(hPolygonVertexPosition); @@ -160,33 +167,42 @@ class PolygonRenderer { glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0); + // use stencilbuffer method for polygon drawing glEnable(GL_STENCIL_TEST); PolygonLayer l = layer; - boolean first = clip; - int cnt = 0; + if (first) { + mCount = 0; + mStart = 0; + } else { + mStart = mCount; + } for (; l != null && l.layer < next; l = l.next) { // fade out polygon layers (set in RederTheme) if (l.area.fade > 0 && l.area.fade > zoom) continue; - if (cnt == 0) { + if (mCount == 0) { + // clear stencilbuffer (tile region) + // disable drawing to framebuffer glColorMask(false, false, false, false); // never pass the test: always apply fail op glStencilFunc(GLES20.GL_ALWAYS, 0, 0xFF); glStencilMask(0xFF); - // glClear(GL_STENCIL_BUFFER_BIT); - // clear stencilbuffer (tile region) glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); if (first) { - // draw clip-region into depth buffer + // draw clip-region into depth buffer: + // this is used for lines and polygons + + // write to depth buffer GLES20.glDepthMask(true); + // to prevent overdraw gl_less restricts // the clip to the area where no other // tile was drawn @@ -197,6 +213,7 @@ class PolygonRenderer { if (first) { first = false; + // dont modify depth buffer GLES20.glDepthMask(false); // only draw to this tile GLES20.glDepthFunc(GLES20.GL_EQUAL); @@ -205,29 +222,50 @@ class PolygonRenderer { // stencil op for stencil method polygon drawing glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT); + // no need for depth test while drawing stencil + glDisable(GLES20.GL_DEPTH_TEST); + + } else if (mCount == mStart) { + // disable drawing to framebuffer + glColorMask(false, false, false, false); + + // never pass the test: always apply fail op + glStencilFunc(GLES20.GL_ALWAYS, 0, 0xFF); + + // stencil op for stencil method polygon drawing + glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT); + // no need for depth test while drawing stencil glDisable(GLES20.GL_DEPTH_TEST); } - mFillPolys[cnt] = l; + + mFillPolys[mCount] = l; // set stencil mask to draw to - glStencilMask(1 << cnt++); + glStencilMask(1 << mCount++); glDrawArrays(GL_TRIANGLE_FAN, l.offset, l.verticesCnt); // draw up to 8 layers into stencil buffer - if (cnt == STENCIL_BITS) { - fillPolygons(cnt, zoom, scale); - cnt = 0; + if (mCount == STENCIL_BITS) { + fillPolygons(zoom, scale); + mCount = 0; + mStart = 0; } } - if (cnt > 0) - fillPolygons(cnt, zoom, scale); + if (mCount > 0) + fillPolygons(zoom, scale); + + // + // if (mCount > 5){ + // mCount = 0; + // mStart = 0; + // } glDisable(GL_STENCIL_TEST); - if (clip && first) + if (first) drawDepthClip(); GLES20.glDisableVertexAttribArray(hPolygonVertexPosition);