- fixed MapViewPosition scaleMap
- fixed GLRender isVisible() for proxy tiles - smoother scale animation
This commit is contained in:
parent
8d57bc7531
commit
7d7cf10d89
@ -44,10 +44,12 @@ public final class MercatorProjection {
|
|||||||
public static final double LONGITUDE_MIN = -LONGITUDE_MAX;
|
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
|
* @param latitude
|
||||||
* the latitude coordinate at which the resolution should be calculated.
|
* the latitude coordinate at which the resolution should be
|
||||||
|
* calculated.
|
||||||
* @param zoomLevel
|
* @param zoomLevel
|
||||||
* the zoom level at which the resolution should be calculated.
|
* the zoom level at which the resolution should be calculated.
|
||||||
* @return the ground resolution at the given latitude and zoom level.
|
* @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
|
* @param latitude
|
||||||
* the latitude coordinate that should be converted.
|
* 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
|
* @param latitude
|
||||||
* the latitude coordinate that should be converted.
|
* the latitude coordinate that should be converted.
|
||||||
@ -103,7 +107,8 @@ public final class MercatorProjection {
|
|||||||
/**
|
/**
|
||||||
* @param longitude
|
* @param longitude
|
||||||
* the longitude value which should be checked.
|
* 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) {
|
public static double limitLongitude(double longitude) {
|
||||||
return Math.max(Math.min(longitude, LONGITUDE_MAX), LONGITUDE_MIN);
|
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
|
* @param longitude
|
||||||
* the longitude coordinate that should be converted.
|
* 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
|
* @param longitude
|
||||||
* the longitude coordinate that should be converted.
|
* 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
|
* @param pixelX
|
||||||
* the pixel X coordinate that should be converted.
|
* 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
|
* @param pixelY
|
||||||
* the pixel Y coordinate that should be converted.
|
* 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
|
* @param tileX
|
||||||
* the tile X number that should be converted.
|
* 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
|
* @param tileY
|
||||||
* the tile Y number that should be converted.
|
* the tile Y number that should be converted.
|
||||||
|
50
src/org/oscim/utils/FastMath.java
Normal file
50
src/org/oscim/utils/FastMath.java
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
32
src/org/oscim/view/DelayedTaskHandler.java
Normal file
32
src/org/oscim/view/DelayedTaskHandler.java
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -83,6 +83,8 @@ public class MapView extends FrameLayout {
|
|||||||
private String mRenderTheme;
|
private String mRenderTheme;
|
||||||
private Map<String, String> mMapOptions;
|
private Map<String, String> mMapOptions;
|
||||||
|
|
||||||
|
// private final Handler mHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param context
|
* @param context
|
||||||
* the enclosing MapActivity instance.
|
* the enclosing MapActivity instance.
|
||||||
@ -124,6 +126,8 @@ public class MapView extends FrameLayout {
|
|||||||
|
|
||||||
MapActivity mapActivity = (MapActivity) context;
|
MapActivity mapActivity = (MapActivity) context;
|
||||||
|
|
||||||
|
// mHandler = new DelayedTaskHandler();
|
||||||
|
|
||||||
debugSettings = new DebugSettings(false, false, false, false);
|
debugSettings = new DebugSettings(false, false, false, false);
|
||||||
|
|
||||||
mMapDatabaseType = mapDatabaseType;
|
mMapDatabaseType = mapDatabaseType;
|
||||||
@ -205,6 +209,29 @@ public class MapView extends FrameLayout {
|
|||||||
return mMapViewPosition;
|
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
|
@Override
|
||||||
public boolean onTouchEvent(MotionEvent motionEvent) {
|
public boolean onTouchEvent(MotionEvent motionEvent) {
|
||||||
// mMapZoomControls.onMapViewTouchEvent(motionEvent.getAction()
|
// mMapZoomControls.onMapViewTouchEvent(motionEvent.getAction()
|
||||||
@ -601,30 +628,6 @@ public class MapView extends FrameLayout {
|
|||||||
mapWorker.proceed();
|
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.
|
// * Sets the visibility of the zoom controls.
|
||||||
// *
|
// *
|
||||||
@ -647,18 +650,4 @@ public class MapView extends FrameLayout {
|
|||||||
// mJobParameters = new JobParameters(mJobParameters.theme, textScale);
|
// mJobParameters = new JobParameters(mJobParameters.theme, textScale);
|
||||||
// clearAndRedrawMapView();
|
// clearAndRedrawMapView();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// public final int
|
|
||||||
// public Handler messageHandler = new Handler() {
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void handleMessage(Message msg) {
|
|
||||||
// switch (msg.what) {
|
|
||||||
// // handle update
|
|
||||||
// // .....
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// };
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,25 +17,35 @@ package org.oscim.view;
|
|||||||
import org.oscim.core.GeoPoint;
|
import org.oscim.core.GeoPoint;
|
||||||
import org.oscim.core.MapPosition;
|
import org.oscim.core.MapPosition;
|
||||||
import org.oscim.core.MercatorProjection;
|
import org.oscim.core.MercatorProjection;
|
||||||
|
import org.oscim.utils.FastMath;
|
||||||
import android.util.FloatMath;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 {
|
public class MapViewPosition {
|
||||||
private static float MAX_SCALE = 2.0f;
|
private static final String TAG = "MapViewPosition";
|
||||||
private static float MIN_SCALE = 1.0f;
|
|
||||||
public static int MAX_ZOOMLEVEL = 16;
|
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 mLatitude;
|
||||||
private double mLongitude;
|
private double mLongitude;
|
||||||
private final MapView mMapView;
|
|
||||||
private byte mZoomLevel;
|
private byte mZoomLevel;
|
||||||
private float mScale;
|
private float mScale;
|
||||||
private float mRotation;
|
private float mRotation;
|
||||||
private float mTilt;
|
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) {
|
MapViewPosition(MapView mapView) {
|
||||||
mMapView = mapView;
|
mMapView = mapView;
|
||||||
|
|
||||||
@ -45,8 +55,24 @@ public class MapViewPosition {
|
|||||||
mScale = 1;
|
mScale = 1;
|
||||||
mRotation = 0.0f;
|
mRotation = 0.0f;
|
||||||
mTilt = 0;
|
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.
|
* @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()
|
* @see #isValid()
|
||||||
*/
|
*/
|
||||||
public synchronized MapPosition getMapPosition() {
|
public synchronized MapPosition getMapPosition() {
|
||||||
if (!isValid()) {
|
if (!isValid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// Log.d("MapViewPosition", "lat: " + mLatitude + " lon: " + mLongitude);
|
// Log.d("MapViewPosition", "lat: " + mLatitude + " lon: " +
|
||||||
|
// mLongitude);
|
||||||
return new MapPosition(mLatitude, mLongitude, mZoomLevel, mScale, mRotation);
|
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) {
|
public synchronized void rotateMap(float angle, float cx, float cy) {
|
||||||
moveMap(cx, cy);
|
moveMap(cx, cy);
|
||||||
// Log.d("MapViewPosition", "rotate:" + angle + " " + (mRotation - angle));
|
// Log.d("MapViewPosition", "rotate:" + angle + " " + (mRotation -
|
||||||
|
// angle));
|
||||||
mRotation -= angle;
|
mRotation -= angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +215,7 @@ public class MapViewPosition {
|
|||||||
mRotation = f;
|
mRotation = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTile(float f) {
|
public void setTilt(float f) {
|
||||||
mTilt = f;
|
mTilt = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,10 +228,12 @@ public class MapViewPosition {
|
|||||||
mLatitude = MercatorProjection.limitLatitude(mapPosition.lat);
|
mLatitude = MercatorProjection.limitLatitude(mapPosition.lat);
|
||||||
mLongitude = MercatorProjection.limitLongitude(mapPosition.lon);
|
mLongitude = MercatorProjection.limitLongitude(mapPosition.lon);
|
||||||
mZoomLevel = mMapView.limitZoomLevel(mapPosition.zoomLevel);
|
mZoomLevel = mMapView.limitZoomLevel(mapPosition.zoomLevel);
|
||||||
|
mMapScale = 1 << mZoomLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void setZoomLevel(byte zoomLevel) {
|
synchronized void setZoomLevel(byte zoomLevel) {
|
||||||
mZoomLevel = mMapView.limitZoomLevel(zoomLevel);
|
mZoomLevel = mMapView.limitZoomLevel(zoomLevel);
|
||||||
|
mMapScale = 1 << mZoomLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void setScale(float scale) {
|
synchronized void setScale(float scale) {
|
||||||
@ -226,79 +257,25 @@ public class MapViewPosition {
|
|||||||
moveMap(pivotX * (1.0f - scale),
|
moveMap(pivotX * (1.0f - scale),
|
||||||
pivotY * (1.0f - scale));
|
pivotY * (1.0f - scale));
|
||||||
|
|
||||||
float s = mScale * scale;
|
float newScale = mMapScale * scale;
|
||||||
|
|
||||||
if (s >= MAX_SCALE) {
|
int z = FastMath.log2((int) newScale);
|
||||||
if (s > 8)
|
|
||||||
|
if (z <= 0 || (z >= MAX_ZOOMLEVEL && mScale >= 8))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mZoomLevel <= MAX_ZOOMLEVEL) {
|
if (z > MAX_ZOOMLEVEL) {
|
||||||
byte z = (byte) FloatMath.sqrt(s);
|
// z16 shows everything, just increase scaling
|
||||||
mZoomLevel += z;
|
if (mScale * scale > 8)
|
||||||
s *= 1.0f / (1 << z);
|
return;
|
||||||
}
|
|
||||||
} else if (s < MIN_SCALE) {
|
mScale *= scale;
|
||||||
byte z = (byte) FloatMath.sqrt(1 / s);
|
mMapScale = newScale;
|
||||||
if (z != 0 && mZoomLevel == 1)
|
|
||||||
return;
|
return;
|
||||||
mZoomLevel -= z;
|
|
||||||
s *= 1 << z;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,8 @@ import android.view.animation.DecelerateInterpolator;
|
|||||||
import android.widget.Scroller;
|
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 {
|
public class TouchHandler {
|
||||||
private static final int INVALID_POINTER_ID = -1;
|
private static final int INVALID_POINTER_ID = -1;
|
||||||
@ -440,7 +441,8 @@ public class TouchHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onScaleEnd(ScaleGestureDetector gd) {
|
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
|
if (mTimer == null && mTimeEnd - mTimeStart < 150
|
||||||
&& (mSumScale < 0.99 || mSumScale > 1.01)) {
|
&& (mSumScale < 0.99 || mSumScale > 1.01)) {
|
||||||
@ -449,7 +451,7 @@ public class TouchHandler {
|
|||||||
|
|
||||||
mZooutOut = mSumScale < 0.99;
|
mZooutOut = mSumScale < 0.99;
|
||||||
|
|
||||||
mTimer = new CountDownTimer((int) mScaleDuration, 30) {
|
mTimer = new CountDownTimer((int) mScaleDuration, 15) {
|
||||||
@Override
|
@Override
|
||||||
public void onTick(long tick) {
|
public void onTick(long tick) {
|
||||||
scale(tick);
|
scale(tick);
|
||||||
@ -468,7 +470,7 @@ public class TouchHandler {
|
|||||||
private float mPrevScale;
|
private float mPrevScale;
|
||||||
private CountDownTimer mTimer;
|
private CountDownTimer mTimer;
|
||||||
boolean mZooutOut;
|
boolean mZooutOut;
|
||||||
private final float mScaleDuration = 350;
|
private final float mScaleDuration = 450;
|
||||||
|
|
||||||
boolean scale(long tick) {
|
boolean scale(long tick) {
|
||||||
|
|
||||||
|
@ -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
|
* 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
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
@ -16,19 +16,12 @@ package org.oscim.view.renderer;
|
|||||||
|
|
||||||
import static android.opengl.GLES20.GL_ARRAY_BUFFER;
|
import static android.opengl.GLES20.GL_ARRAY_BUFFER;
|
||||||
import static android.opengl.GLES20.GL_BLEND;
|
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_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_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.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.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
@ -69,7 +62,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
private static ArrayList<VertexBufferObject> mVBOs;
|
private static ArrayList<VertexBufferObject> mVBOs;
|
||||||
|
|
||||||
private static int mWidth, mHeight;
|
private static int mWidth, mHeight;
|
||||||
private static float mAspect;
|
|
||||||
|
|
||||||
private static int rotateBuffers = 2;
|
private static int rotateBuffers = 2;
|
||||||
private static ShortBuffer shortBuffer[];
|
private static ShortBuffer shortBuffer[];
|
||||||
@ -86,12 +78,12 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
private static float[] mProjMatrix = new float[16];
|
private static float[] mProjMatrix = new float[16];
|
||||||
private static float[] mProjMatrixI = new float[16];
|
private static float[] mProjMatrixI = new float[16];
|
||||||
|
|
||||||
// curTiles is set by TileLoader and swapped with
|
// mNextTiles is set by TileLoader and swapped with
|
||||||
// drawTiles in onDrawFrame in GL thread.
|
// mDrawTiles in onDrawFrame in GL thread.
|
||||||
private static TilesData curTiles, drawTiles;
|
private static TilesData mNextTiles, mDrawTiles;
|
||||||
|
|
||||||
// flag set by updateVisibleList when current visible tiles
|
// 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 boolean mUpdateTiles;
|
||||||
|
|
||||||
private static MapPosition mCurPosition;
|
private static MapPosition mCurPosition;
|
||||||
@ -147,7 +139,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
* current MapPosition
|
* current MapPosition
|
||||||
* @param tiles
|
* @param tiles
|
||||||
* active tiles
|
* active tiles
|
||||||
* @return curTiles (the previously active tiles)
|
* @return mNextTiles (the previously active tiles)
|
||||||
*/
|
*/
|
||||||
static TilesData updateTiles(MapPosition mapPosition, TilesData tiles) {
|
static TilesData updateTiles(MapPosition mapPosition, TilesData tiles) {
|
||||||
GLRenderer.tilelock.lock();
|
GLRenderer.tilelock.lock();
|
||||||
@ -155,8 +147,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
mCurPosition = mapPosition;
|
mCurPosition = mapPosition;
|
||||||
|
|
||||||
// unlock previously active tiles
|
// unlock previously active tiles
|
||||||
for (int i = 0; i < curTiles.cnt; i++) {
|
for (int i = 0; i < mNextTiles.cnt; i++) {
|
||||||
MapTile t = curTiles.tiles[i];
|
MapTile t = mNextTiles.tiles[i];
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
|
|
||||||
for (int j = 0; j < tiles.cnt; j++) {
|
for (int j = 0; j < tiles.cnt; j++) {
|
||||||
@ -168,8 +160,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
if (found)
|
if (found)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (int j = 0; j < drawTiles.cnt; j++) {
|
for (int j = 0; j < mDrawTiles.cnt; j++) {
|
||||||
if (drawTiles.tiles[j] == t) {
|
if (mDrawTiles.tiles[j] == t) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -180,22 +172,23 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
t.unlock();
|
t.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
TilesData tmp = curTiles;
|
TilesData tmp = mNextTiles;
|
||||||
curTiles = tiles;
|
mNextTiles = tiles;
|
||||||
|
|
||||||
// lock tiles (and their proxies) to not be removed from cache
|
// lock tiles (and their proxies) to not be removed from cache
|
||||||
for (int i = 0; i < curTiles.cnt; i++) {
|
for (int i = 0; i < mNextTiles.cnt; i++) {
|
||||||
MapTile t = curTiles.tiles[i];
|
MapTile t = mNextTiles.tiles[i];
|
||||||
if (!t.isActive)
|
if (!t.isActive)
|
||||||
t.lock();
|
t.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < drawTiles.cnt; j++) {
|
for (int j = 0; j < mDrawTiles.cnt; j++) {
|
||||||
MapTile t = drawTiles.tiles[j];
|
MapTile t = mDrawTiles.tiles[j];
|
||||||
if (!t.isActive)
|
if (!t.isActive)
|
||||||
t.lock();
|
t.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GLThread flips mNextTiles with mDrawTiles
|
||||||
mUpdateTiles = true;
|
mUpdateTiles = true;
|
||||||
|
|
||||||
GLRenderer.tilelock.unlock();
|
GLRenderer.tilelock.unlock();
|
||||||
@ -236,46 +229,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
mUpdateColor = true;
|
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 int uploadCnt = 0;
|
||||||
|
|
||||||
private boolean uploadTileData(MapTile tile) {
|
private boolean uploadTileData(MapTile tile) {
|
||||||
@ -308,7 +261,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log.d(TAG, "uploadTileData, " + tile);
|
// Log.d(TAG, "uploadTileData, " + tile);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id);
|
GLES20.glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id);
|
||||||
|
|
||||||
sbuf = shortBuffer[uploadCnt];
|
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...
|
// FIXME probably not a good idea to do this in gl thread...
|
||||||
if (sbuf == null || sbuf.capacity() < newSize) {
|
if (sbuf == null || sbuf.capacity() < newSize) {
|
||||||
ByteBuffer bbuf = ByteBuffer.allocateDirect(newSize * SHORT_BYTES).order(
|
ByteBuffer bbuf = ByteBuffer.allocateDirect(newSize * SHORT_BYTES)
|
||||||
ByteOrder.nativeOrder());
|
.order(ByteOrder.nativeOrder());
|
||||||
sbuf = bbuf.asShortBuffer();
|
sbuf = bbuf.asShortBuffer();
|
||||||
shortBuffer[uploadCnt] = sbuf;
|
shortBuffer[uploadCnt] = sbuf;
|
||||||
sbuf.put(mFillCoords, 0, 8);
|
sbuf.put(mFillCoords, 0, 8);
|
||||||
@ -346,7 +299,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
sbuf.flip();
|
sbuf.flip();
|
||||||
|
|
||||||
if (newSize != sbuf.remaining()) {
|
if (newSize != sbuf.remaining()) {
|
||||||
|
|
||||||
Log.d(TAG, "tiles wrong: " + tile + " "
|
Log.d(TAG, "tiles wrong: " + tile + " "
|
||||||
+ newSize + " "
|
+ newSize + " "
|
||||||
+ sbuf.position() + " "
|
+ sbuf.position() + " "
|
||||||
@ -361,13 +313,16 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
}
|
}
|
||||||
newSize *= SHORT_BYTES;
|
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
|
if (tile.vbo.size > newSize && tile.vbo.size < newSize * 4
|
||||||
&& mBufferMemoryUsage < LIMIT_BUFFERS) {
|
&& mBufferMemoryUsage < LIMIT_BUFFERS) {
|
||||||
GLES20.glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, sbuf);
|
GLES20.glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, sbuf);
|
||||||
|
// Log.d(TAG, "reuse buffer " + tile.vbo.size + " " + newSize);
|
||||||
} else {
|
} else {
|
||||||
mBufferMemoryUsage -= tile.vbo.size;
|
mBufferMemoryUsage -= tile.vbo.size;
|
||||||
tile.vbo.size = newSize;
|
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;
|
mBufferMemoryUsage += tile.vbo.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,13 +335,19 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void checkBufferUsage() {
|
private static void checkBufferUsage() {
|
||||||
|
if (mBufferMemoryUsage < LIMIT_BUFFERS) {
|
||||||
|
if (CACHE_TILES < CACHE_TILES_MAX)
|
||||||
|
CACHE_TILES += 50;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// try to clear some unused vbo when exceding limit
|
// try to clear some unused vbo when exceding limit
|
||||||
if (mBufferMemoryUsage > LIMIT_BUFFERS) {
|
|
||||||
Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / MB + "MB");
|
Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / MB + "MB");
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
int vboIds[] = new int[10];
|
||||||
int buf[] = new int[1];
|
VertexBufferObject[] tmp = new VertexBufferObject[10];
|
||||||
|
|
||||||
|
int removed = 0;
|
||||||
synchronized (mVBOs) {
|
synchronized (mVBOs) {
|
||||||
for (VertexBufferObject vbo : mVBOs) {
|
for (VertexBufferObject vbo : mVBOs) {
|
||||||
|
|
||||||
@ -394,33 +355,76 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
mBufferMemoryUsage -= vbo.size;
|
mBufferMemoryUsage -= vbo.size;
|
||||||
|
vbo.size = 0;
|
||||||
|
|
||||||
// this should free allocated memory but it does not.
|
// this should free allocated memory but it does not.
|
||||||
// on HTC it causes oom exception?!
|
// on HTC it causes OOM exception?!
|
||||||
|
|
||||||
// glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
|
// glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
|
||||||
// glBufferData(GL_ARRAY_BUFFER, 0, null,
|
// glBufferData(GL_ARRAY_BUFFER, 0, null,
|
||||||
// GLES20.GL_STATIC_DRAW);
|
// GLES20.GL_STATIC_DRAW);
|
||||||
|
|
||||||
// recreate vbo instead
|
// recreate vbo instead
|
||||||
buf[0] = vbo.id;
|
vboIds[removed] = vbo.id;
|
||||||
GLES20.glDeleteBuffers(1, buf, 0);
|
tmp[removed++] = vbo;
|
||||||
GLES20.glGenBuffers(1, buf, 0);
|
|
||||||
vbo.id = buf[0];
|
|
||||||
|
|
||||||
vbo.size = 0;
|
if (removed == 10)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
if (removed > 0) {
|
||||||
Log.d(TAG, " > " + mBufferMemoryUsage / MB + "MB");
|
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)
|
if (mBufferMemoryUsage > LIMIT_BUFFERS && CACHE_TILES > 100)
|
||||||
CACHE_TILES -= 50;
|
CACHE_TILES -= 50;
|
||||||
|
|
||||||
} else if (CACHE_TILES < CACHE_TILES_MAX) {
|
|
||||||
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;
|
private static boolean mRotate = false;
|
||||||
@ -429,17 +433,16 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
float div, boolean project) {
|
float div, boolean project) {
|
||||||
float x, y, scale;
|
float x, y, scale;
|
||||||
|
|
||||||
// if (mRotate) {
|
|
||||||
scale = mapPosition.scale / (div * COORD_MULTIPLIER);
|
scale = mapPosition.scale / (div * COORD_MULTIPLIER);
|
||||||
x = (float) (tile.pixelX - mapPosition.x * div);
|
x = (float) (tile.pixelX - mapPosition.x * div);
|
||||||
y = (float) (tile.pixelY - mapPosition.y * div);
|
y = (float) (tile.pixelY - mapPosition.y * div);
|
||||||
|
|
||||||
Matrix.setIdentityM(matrix, 0);
|
Matrix.setIdentityM(matrix, 0);
|
||||||
|
|
||||||
// scale to tile coordinates
|
// scale to tile to world coordinates
|
||||||
Matrix.scaleM(matrix, 0, scale, scale, 1);
|
Matrix.scaleM(matrix, 0, scale, scale, 1);
|
||||||
|
|
||||||
// translate relative to center
|
// translate relative to map center
|
||||||
Matrix.translateM(matrix, 0,
|
Matrix.translateM(matrix, 0,
|
||||||
x * COORD_MULTIPLIER,
|
x * COORD_MULTIPLIER,
|
||||||
-(y + Tile.TILE_SIZE) * COORD_MULTIPLIER,
|
-(y + Tile.TILE_SIZE) * COORD_MULTIPLIER,
|
||||||
@ -450,44 +453,31 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
|
|
||||||
if (project)
|
if (project)
|
||||||
Matrix.multiplyMM(matrix, 0, mProjMatrix, 0, matrix, 0);
|
Matrix.multiplyMM(matrix, 0, mProjMatrix, 0, matrix, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// } else {
|
// private float[] mv = new float[4];
|
||||||
// scale = (float) (2.0 * mapPosition.scale / (mHeight * div));
|
// private float[] mu = { 1, 1, -1, 1 };
|
||||||
// x = (float) (tile.pixelX - mapPosition.x * div);
|
|
||||||
// y = (float) (tile.pixelY - mapPosition.y * div);
|
|
||||||
//
|
//
|
||||||
// matrix[12] = x * scale * mAspect;
|
// private float[] mUnprojMatrix = new float[16];
|
||||||
// matrix[13] = -(y + Tile.TILE_SIZE) * scale;
|
//
|
||||||
// // increase the 'distance' with each tile drawn.
|
// private void unproject(MapPosition pos, float x, float y) {
|
||||||
// matrix[14] = -0.99f + offset * 0.01f;
|
// mu[0] = x;
|
||||||
// matrix[0] = scale * mAspect / COORD_MULTIPLIER;
|
// mu[1] = y;
|
||||||
// matrix[5] = scale / COORD_MULTIPLIER;
|
// 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
|
@Override
|
||||||
public void onDrawFrame(GL10 glUnused) {
|
public void onDrawFrame(GL10 glUnused) {
|
||||||
@ -498,30 +488,27 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
if (MapView.debugFrameTime)
|
if (MapView.debugFrameTime)
|
||||||
start = SystemClock.uptimeMillis();
|
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);
|
GLES20.glDepthMask(true);
|
||||||
|
GLES20.glStencilMask(0xFF);
|
||||||
// Note: having the impression it is faster to also clear the
|
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT
|
||||||
// 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.GL_DEPTH_BUFFER_BIT
|
| GLES20.GL_DEPTH_BUFFER_BIT
|
||||||
// | GLES20.GL_STENCIL_BUFFER_BIT
|
| GLES20.GL_STENCIL_BUFFER_BIT);
|
||||||
);
|
|
||||||
|
|
||||||
// get position and current tiles to draw
|
// get position and current tiles to draw
|
||||||
GLRenderer.tilelock.lock();
|
GLRenderer.tilelock.lock();
|
||||||
mapPosition = mCurPosition;
|
mapPosition = mCurPosition;
|
||||||
|
|
||||||
if (mUpdateTiles) {
|
if (mUpdateTiles) {
|
||||||
TilesData tmp = drawTiles;
|
TilesData tmp = mDrawTiles;
|
||||||
drawTiles = curTiles;
|
mDrawTiles = mNextTiles;
|
||||||
curTiles = tmp;
|
mNextTiles = tmp;
|
||||||
mUpdateTiles = false;
|
mUpdateTiles = false;
|
||||||
}
|
}
|
||||||
GLRenderer.tilelock.unlock();
|
GLRenderer.tilelock.unlock();
|
||||||
|
|
||||||
if (drawTiles == null)
|
if (mDrawTiles == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// if (mRotate != (mMapView.enableRotation || mMapView.enableCompass)) {
|
// if (mRotate != (mMapView.enableRotation || mMapView.enableCompass)) {
|
||||||
@ -572,12 +559,13 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mUpdateColor && mClearColor != null) {
|
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;
|
mUpdateColor = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tileCnt = drawTiles.cnt;
|
int tileCnt = mDrawTiles.cnt;
|
||||||
MapTile[] tiles = drawTiles.tiles;
|
MapTile[] tiles = mDrawTiles.tiles;
|
||||||
|
|
||||||
uploadCnt = 0;
|
uploadCnt = 0;
|
||||||
int updateTextures = 0;
|
int updateTextures = 0;
|
||||||
@ -586,7 +574,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
for (int i = 0; i < tileCnt; i++) {
|
for (int i = 0; i < tileCnt; i++) {
|
||||||
MapTile tile = tiles[i];
|
MapTile tile = tiles[i];
|
||||||
|
|
||||||
if (!isVisible(mapPosition, tile, 1))
|
if (!isVisible(mapPosition, tile))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (tile.texture == null && TextRenderer.drawToTexture(tile))
|
if (tile.texture == null && TextRenderer.drawToTexture(tile))
|
||||||
@ -621,32 +609,29 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
if (updateTextures > 0)
|
if (updateTextures > 0)
|
||||||
TextRenderer.compileTextures();
|
TextRenderer.compileTextures();
|
||||||
|
|
||||||
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
|
GLES20.glEnable(GL_DEPTH_TEST);
|
||||||
GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL);
|
GLES20.glEnable(GL_POLYGON_OFFSET_FILL);
|
||||||
|
|
||||||
for (int i = 0; i < tileCnt; i++) {
|
for (int i = 0; i < tileCnt; i++) {
|
||||||
if (tiles[i].isVisible && tiles[i].isReady) {
|
if (tiles[i].isVisible && tiles[i].isReady)
|
||||||
drawTile(mapPosition, tiles[i], 1);
|
drawTile(mapPosition, tiles[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// proxies are clipped to the region where nothing was drawn to depth
|
// proxies are clipped to the region where nothing was drawn to depth
|
||||||
// buffer
|
// buffer. TODO draw all parent before grandparent
|
||||||
// TODO draw all parent before grandparent
|
|
||||||
for (int i = 0; i < tileCnt; i++) {
|
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]);
|
drawProxyTile(mapPosition, tiles[i]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// GlUtils.checkGlError("end draw");
|
// GlUtils.checkGlError("end draw");
|
||||||
|
|
||||||
GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL);
|
GLES20.glDisable(GL_POLYGON_OFFSET_FILL);
|
||||||
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
|
GLES20.glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
mDrawCount = 0;
|
mDrawCount = 0;
|
||||||
mDrawSerial++;
|
mDrawSerial++;
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
GLES20.glEnable(GL_BLEND);
|
||||||
int z = mapPosition.zoomLevel;
|
int z = mapPosition.zoomLevel;
|
||||||
float s = mapPosition.scale;
|
float s = mapPosition.scale;
|
||||||
|
|
||||||
@ -683,11 +668,20 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
// used to not draw a tile twice per frame...
|
// used to not draw a tile twice per frame...
|
||||||
private static byte mDrawSerial = 0;
|
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
|
// draw parents only once
|
||||||
if (tile.lastDraw == mDrawSerial)
|
if (tile.lastDraw == mDrawSerial)
|
||||||
return;
|
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;
|
tile.lastDraw = mDrawSerial;
|
||||||
|
|
||||||
int z = mapPosition.zoomLevel;
|
int z = mapPosition.zoomLevel;
|
||||||
@ -698,7 +692,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
|
|
||||||
GLES20.glPolygonOffset(0, mDrawCount++);
|
GLES20.glPolygonOffset(0, mDrawCount++);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id);
|
GLES20.glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id);
|
||||||
|
|
||||||
LineLayer ll = tile.lineLayers;
|
LineLayer ll = tile.lineLayers;
|
||||||
PolygonLayer pl = tile.polygonLayers;
|
PolygonLayer pl = tile.polygonLayers;
|
||||||
@ -716,10 +710,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
pnext = pl.layer;
|
pnext = pl.layer;
|
||||||
|
|
||||||
if (pl != null && pnext < lnext) {
|
if (pl != null && pnext < lnext) {
|
||||||
glDisable(GL_BLEND);
|
GLES20.glDisable(GL_BLEND);
|
||||||
|
|
||||||
pl = PolygonRenderer.drawPolygons(pl, lnext, mvp, z, s,
|
pl = PolygonRenderer.drawPolygons(pl, lnext, mvp, z, s, !clipped);
|
||||||
!clipped);
|
|
||||||
|
|
||||||
clipped = true;
|
clipped = true;
|
||||||
|
|
||||||
@ -730,7 +723,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
clipped = true;
|
clipped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -747,13 +740,13 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
if (c == null)
|
if (c == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!isVisible(mapPosition, c, 2)) {
|
if (!isVisible(mapPosition, c)) {
|
||||||
drawn++;
|
drawn++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c.isReady) {
|
if (c.isReady) {
|
||||||
drawTile(mapPosition, c, 2);
|
drawTile(mapPosition, c);
|
||||||
drawn++;
|
drawn++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -762,36 +755,38 @@ 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) {
|
||||||
|
boolean drawn = false;
|
||||||
if (mapPosition.scale > 1.5f) {
|
if (mapPosition.scale > 1.5f) {
|
||||||
// prefer drawing children
|
// prefer drawing children
|
||||||
if (!drawProxyChild(mapPosition, tile)) {
|
if (!drawProxyChild(mapPosition, tile)) {
|
||||||
|
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
|
||||||
MapTile t = tile.rel.parent.tile;
|
MapTile t = tile.rel.parent.tile;
|
||||||
if (t != null) {
|
|
||||||
if (t.isReady) {
|
if (t.isReady) {
|
||||||
drawTile(mapPosition, t, 0.5f);
|
drawTile(mapPosition, t);
|
||||||
} else {
|
drawn = true;
|
||||||
MapTile p = t.rel.parent.tile;
|
|
||||||
if (p != null && p.isReady)
|
|
||||||
drawTile(mapPosition, p, 0.25f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!drawn && (tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
|
||||||
|
MapTile t = tile.rel.parent.parent.tile;
|
||||||
|
if (t.isReady)
|
||||||
|
drawTile(mapPosition, t);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// prefer drawing parent
|
// prefer drawing parent
|
||||||
MapTile t = tile.rel.parent.tile;
|
MapTile t = tile.rel.parent.tile;
|
||||||
|
|
||||||
if (t != null && t.isReady) {
|
if (t != null && t.isReady) {
|
||||||
drawTile(mapPosition, t, 0.5f);
|
drawTile(mapPosition, t);
|
||||||
|
|
||||||
} else if (!drawProxyChild(mapPosition, tile)) {
|
} else if (!drawProxyChild(mapPosition, tile)) {
|
||||||
|
|
||||||
// need to check rel.parent here, t could alread be root
|
if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
|
||||||
if (t != null) {
|
t = tile.rel.parent.parent.tile;
|
||||||
t = t.rel.parent.tile;
|
if (t.isReady)
|
||||||
|
drawTile(mapPosition, t);
|
||||||
if (t != null && t.isReady)
|
|
||||||
drawTile(mapPosition, t, 0.25f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -811,8 +806,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
mWidth = width;
|
mWidth = width;
|
||||||
mHeight = height;
|
mHeight = height;
|
||||||
|
|
||||||
mAspect = (float) height / width;
|
|
||||||
|
|
||||||
// Matrix.orthoM(mProjMatrix, 0, -0.5f / mAspect, 0.5f / mAspect, -0.5f,
|
// Matrix.orthoM(mProjMatrix, 0, -0.5f / mAspect, 0.5f / mAspect, -0.5f,
|
||||||
// 0.5f, -1, 1);
|
// 0.5f, -1, 1);
|
||||||
|
|
||||||
@ -828,7 +821,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
mProjMatrix[10] = 0;
|
mProjMatrix[10] = 0;
|
||||||
mProjMatrix[14] = 0;
|
mProjMatrix[14] = 0;
|
||||||
|
|
||||||
glViewport(0, 0, width, height);
|
GLES20.glViewport(0, 0, width, height);
|
||||||
|
|
||||||
if (!changed && !mNewSurface) {
|
if (!changed && !mNewSurface) {
|
||||||
mMapView.redrawMap();
|
mMapView.redrawMap();
|
||||||
@ -845,7 +838,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
// Set up vertex buffer objects
|
// Set up vertex buffer objects
|
||||||
int numVBO = (CACHE_TILES + (numTiles * 2));
|
int numVBO = (CACHE_TILES + (numTiles * 2));
|
||||||
int[] mVboIds = new int[numVBO];
|
int[] mVboIds = new int[numVBO];
|
||||||
glGenBuffers(numVBO, mVboIds, 0);
|
GLES20.glGenBuffers(numVBO, mVboIds, 0);
|
||||||
GlUtils.checkGlError("glGenBuffers");
|
GlUtils.checkGlError("glGenBuffers");
|
||||||
|
|
||||||
mVBOs = new ArrayList<VertexBufferObject>(numVBO);
|
mVBOs = new ArrayList<VertexBufferObject>(numVBO);
|
||||||
@ -857,22 +850,22 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
TextRenderer.setup(numTiles);
|
TextRenderer.setup(numTiles);
|
||||||
|
|
||||||
if (mClearColor != null) {
|
if (mClearColor != null) {
|
||||||
glClearColor(mClearColor[0], mClearColor[1],
|
GLES20.glClearColor(mClearColor[0], mClearColor[1],
|
||||||
mClearColor[2], mClearColor[3]);
|
mClearColor[2], mClearColor[3]);
|
||||||
} else {
|
} else {
|
||||||
glClearColor(0.98f, 0.98f, 0.97f, 1.0f);
|
GLES20.glClearColor(0.98f, 0.98f, 0.97f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
GlUtils.checkGlError("onSurfaceChanged");
|
GlUtils.checkGlError("onSurfaceChanged");
|
||||||
|
|
||||||
glClear(GL_STENCIL_BUFFER_BIT);
|
GLES20.glClear(GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
mMapView.redrawMap();
|
mMapView.redrawMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearTiles(int numTiles) {
|
void clearTiles(int numTiles) {
|
||||||
drawTiles = new TilesData(numTiles);
|
mDrawTiles = new TilesData(numTiles);
|
||||||
curTiles = new TilesData(numTiles);
|
mNextTiles = new TilesData(numTiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -904,9 +897,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
|
|||||||
|
|
||||||
// glEnable(GL_SCISSOR_TEST);
|
// glEnable(GL_SCISSOR_TEST);
|
||||||
// glScissor(0, 0, mWidth, mHeight);
|
// glScissor(0, 0, mWidth, mHeight);
|
||||||
glClearStencil(0);
|
GLES20.glClearStencil(0);
|
||||||
glDisable(GLES20.GL_CULL_FACE);
|
GLES20.glDisable(GLES20.GL_CULL_FACE);
|
||||||
glBlendFunc(GLES20.GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
GLES20.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,8 @@ class LineLayer {
|
|||||||
private static final float COORD_SCALE = GLRenderer.COORD_MULTIPLIER;
|
private static final float COORD_SCALE = GLRenderer.COORD_MULTIPLIER;
|
||||||
// scale factor mapping extrusion vector to short values
|
// scale factor mapping extrusion vector to short values
|
||||||
private static final float DIR_SCALE = 2048;
|
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;
|
private static final int DIR_MASK = 0xFFFFFFFC;
|
||||||
|
|
||||||
// next layer
|
// 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) {
|
void addLine(float[] points, short[] index, boolean closed) {
|
||||||
|
@ -62,11 +62,10 @@ class LineRenderer {
|
|||||||
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) {
|
||||||
|
|
||||||
float z = 1 / div;
|
|
||||||
|
|
||||||
if (layer == null)
|
if (layer == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
// TODO should use fast line program when view is not tilted
|
||||||
GLES20.glUseProgram(lineProgram);
|
GLES20.glUseProgram(lineProgram);
|
||||||
|
|
||||||
GLES20.glEnableVertexAttribArray(hLineVertexPosition);
|
GLES20.glEnableVertexAttribArray(hLineVertexPosition);
|
||||||
@ -81,7 +80,9 @@ class LineRenderer {
|
|||||||
GLES20.glUniformMatrix4fv(hLineMatrix, 1, false, matrix, 0);
|
GLES20.glUniformMatrix4fv(hLineMatrix, 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:
|
||||||
float pixel = 2.0f / (scale * z);
|
// only works with orthographic projection
|
||||||
|
float s = scale / div;
|
||||||
|
float pixel = 2.0f / s;
|
||||||
|
|
||||||
if (mFast)
|
if (mFast)
|
||||||
GLES20.glUniform1f(hLineScale, pixel);
|
GLES20.glUniform1f(hLineScale, pixel);
|
||||||
@ -89,7 +90,7 @@ class LineRenderer {
|
|||||||
GLES20.glUniform1f(hLineScale, 0);
|
GLES20.glUniform1f(hLineScale, 0);
|
||||||
|
|
||||||
// line scale factor (for non fixed lines)
|
// line scale factor (for non fixed lines)
|
||||||
float s = FloatMath.sqrt(scale * z);
|
float lineScale = FloatMath.sqrt(s);
|
||||||
boolean blur = false;
|
boolean blur = false;
|
||||||
|
|
||||||
LineLayer l = layer;
|
LineLayer l = layer;
|
||||||
@ -117,33 +118,31 @@ 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) / (scale * z)
|
GLES20.glUniform1f(hLineScale, (l.width + o.width) / s
|
||||||
- (line.blur / (scale * z)));
|
- (line.blur / s));
|
||||||
blur = true;
|
blur = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zoom > TileGenerator.STROKE_MAX_ZOOM_LEVEL)
|
if (zoom > TileGenerator.STROKE_MAX_ZOOM_LEVEL)
|
||||||
GLES20.glUniform1f(hLineWidth,
|
GLES20.glUniform1f(hLineWidth, (l.width + o.width) / s);
|
||||||
(l.width + o.width) / (scale * z));
|
|
||||||
else
|
else
|
||||||
GLES20.glUniform1f(hLineWidth, l.width / (scale * z)
|
GLES20.glUniform1f(hLineWidth, l.width / s + o.width / lineScale);
|
||||||
+ o.width / s);
|
|
||||||
|
|
||||||
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 / s) * line.blur);
|
GLES20.glUniform1f(hLineScale, (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 / (scale * z)));
|
GLES20.glUniform1f(hLineWidth, l.width / s);
|
||||||
} else {
|
} else {
|
||||||
GLES20.glUniform1f(hLineWidth, (l.width / s));
|
GLES20.glUniform1f(hLineWidth, l.width / lineScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, l.offset, l.verticesCnt);
|
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, l.offset, l.verticesCnt);
|
||||||
|
@ -91,13 +91,10 @@ public class MapRenderer extends GLSurfaceView {
|
|||||||
mInitial = true;
|
mInitial = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* called by MapView when position or map settings changes
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* Update list of visible tiles and passes them to MapRenderer, when not
|
* Update list of visible tiles and passes them to MapRenderer, when not
|
||||||
* available tiles are created and added to JobQueue (mapView.addJobs) for
|
* available tiles are created and added to JobQueue (mapView.addJobs) for
|
||||||
* loading by MapGenerator class
|
* loading by TileGenerator class
|
||||||
*
|
*
|
||||||
* @param clear
|
* @param clear
|
||||||
* ...
|
* ...
|
||||||
@ -108,7 +105,7 @@ public class MapRenderer extends GLSurfaceView {
|
|||||||
boolean changedPos = false;
|
boolean changedPos = false;
|
||||||
boolean changedZoom = false;
|
boolean changedZoom = false;
|
||||||
|
|
||||||
if (mMapView == null || mMapView.getMapPosition() == null)
|
if (mMapView == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MapPosition mapPosition = mMapView.getMapPosition().getMapPosition();
|
MapPosition mapPosition = mMapView.getMapPosition().getMapPosition();
|
||||||
@ -121,14 +118,17 @@ public class MapRenderer extends GLSurfaceView {
|
|||||||
if (clear) {
|
if (clear) {
|
||||||
// remove all tiles references
|
// remove all tiles references
|
||||||
Log.d(TAG, "CLEAR");
|
Log.d(TAG, "CLEAR");
|
||||||
synchronized (GLRenderer.lock) {
|
|
||||||
|
GLRenderer.tilelock.lock();
|
||||||
|
|
||||||
for (MapTile t : mTiles)
|
for (MapTile t : mTiles)
|
||||||
clearTile(t);
|
clearTile(t);
|
||||||
|
|
||||||
mTiles.clear();
|
mTiles.clear();
|
||||||
mTilesLoaded.clear();
|
mTilesLoaded.clear();
|
||||||
QuadTree.init();
|
QuadTree.init();
|
||||||
}
|
GLRenderer.tilelock.unlock();
|
||||||
|
|
||||||
mInitial = true;
|
mInitial = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,21 +180,29 @@ public class MapRenderer extends GLSurfaceView {
|
|||||||
mTileY = tileY;
|
mTileY = tileY;
|
||||||
mPrevZoom = zoomLevel;
|
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)
|
if (!MapView.debugFrameTime)
|
||||||
requestRender();
|
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);
|
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) {
|
if (changedPos || changedZoom) {
|
||||||
int remove = mTiles.size() - GLRenderer.CACHE_TILES;
|
int remove = mTiles.size() - GLRenderer.CACHE_TILES;
|
||||||
if (remove > 50)
|
if (remove > 50)
|
||||||
@ -202,7 +210,6 @@ public class MapRenderer extends GLSurfaceView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
limitLoadQueue();
|
limitLoadQueue();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,7 +19,8 @@ import org.oscim.view.generator.JobTile;
|
|||||||
class MapTile extends 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;
|
VertexBufferObject vbo;
|
||||||
|
|
||||||
@ -65,8 +66,8 @@ class MapTile extends JobTile {
|
|||||||
byte lastDraw = 0;
|
byte lastDraw = 0;
|
||||||
|
|
||||||
// keep track which tiles are locked as proxy for this tile
|
// keep track which tiles are locked as proxy for this tile
|
||||||
// 16: parent
|
final static int PROXY_PARENT = 16;
|
||||||
// 32: grandparent
|
final static int PROXY_GRAMPA = 32;
|
||||||
// 1-8: children
|
// 1-8: children
|
||||||
byte proxies;
|
byte proxies;
|
||||||
|
|
||||||
@ -99,12 +100,12 @@ class MapTile extends JobTile {
|
|||||||
MapTile p = rel.parent.tile;
|
MapTile p = rel.parent.tile;
|
||||||
|
|
||||||
if (p != null && (p.isReady || p.newData || p.isLoading)) {
|
if (p != null && (p.isReady || p.newData || p.isLoading)) {
|
||||||
proxies |= (1 << 4);
|
proxies |= PROXY_PARENT;
|
||||||
p.refs++;
|
p.refs++;
|
||||||
} else {
|
} 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 |= (1 << 5);
|
proxies |= PROXY_GRAMPA;
|
||||||
p.refs++;
|
p.refs++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,8 @@ import org.oscim.utils.GlUtils;
|
|||||||
import android.opengl.GLES20;
|
import android.opengl.GLES20;
|
||||||
|
|
||||||
class PolygonRenderer {
|
class PolygonRenderer {
|
||||||
|
private static final String TAG = "PolygonRenderer";
|
||||||
|
|
||||||
private static final int NUM_VERTEX_SHORTS = 2;
|
private static final int NUM_VERTEX_SHORTS = 2;
|
||||||
private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0;
|
private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0;
|
||||||
private static int STENCIL_BITS = 8;
|
private static int STENCIL_BITS = 8;
|
||||||
@ -71,7 +73,7 @@ class PolygonRenderer {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void fillPolygons(int count, double zoom, float scale) {
|
private static void fillPolygons(double zoom, float scale) {
|
||||||
boolean blend = false;
|
boolean blend = false;
|
||||||
|
|
||||||
/* draw to framebuffer */
|
/* draw to framebuffer */
|
||||||
@ -83,7 +85,7 @@ class PolygonRenderer {
|
|||||||
/* only draw where nothing was drawn yet */
|
/* only draw where nothing was drawn yet */
|
||||||
glEnable(GLES20.GL_DEPTH_TEST);
|
glEnable(GLES20.GL_DEPTH_TEST);
|
||||||
|
|
||||||
for (int c = 0; c < count; c++) {
|
for (int c = mStart; c < mCount; c++) {
|
||||||
PolygonLayer l = mFillPolys[c];
|
PolygonLayer l = mFillPolys[c];
|
||||||
|
|
||||||
float f = 1.0f;
|
float f = 1.0f;
|
||||||
@ -149,8 +151,13 @@ class PolygonRenderer {
|
|||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PolygonLayer drawPolygons(PolygonLayer layer, int next,
|
// layers to fill
|
||||||
float[] matrix, double zoom, float scale, boolean clip) {
|
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);
|
glUseProgram(polygonProgram);
|
||||||
GLES20.glEnableVertexAttribArray(hPolygonVertexPosition);
|
GLES20.glEnableVertexAttribArray(hPolygonVertexPosition);
|
||||||
@ -160,33 +167,42 @@ class PolygonRenderer {
|
|||||||
|
|
||||||
glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0);
|
glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0);
|
||||||
|
|
||||||
|
// use stencilbuffer method for polygon drawing
|
||||||
glEnable(GL_STENCIL_TEST);
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
PolygonLayer l = layer;
|
PolygonLayer l = layer;
|
||||||
|
|
||||||
boolean first = clip;
|
if (first) {
|
||||||
int cnt = 0;
|
mCount = 0;
|
||||||
|
mStart = 0;
|
||||||
|
} else {
|
||||||
|
mStart = mCount;
|
||||||
|
}
|
||||||
|
|
||||||
for (; l != null && l.layer < next; l = l.next) {
|
for (; l != null && l.layer < next; l = l.next) {
|
||||||
// fade out polygon layers (set in RederTheme)
|
// fade out polygon layers (set in RederTheme)
|
||||||
if (l.area.fade > 0 && l.area.fade > zoom)
|
if (l.area.fade > 0 && l.area.fade > zoom)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (cnt == 0) {
|
if (mCount == 0) {
|
||||||
|
// clear stencilbuffer (tile region)
|
||||||
|
|
||||||
// disable drawing to framebuffer
|
// disable drawing to framebuffer
|
||||||
glColorMask(false, false, false, false);
|
glColorMask(false, false, false, false);
|
||||||
|
|
||||||
// never pass the test: always apply fail op
|
// never pass the test: always apply fail op
|
||||||
glStencilFunc(GLES20.GL_ALWAYS, 0, 0xFF);
|
glStencilFunc(GLES20.GL_ALWAYS, 0, 0xFF);
|
||||||
glStencilMask(0xFF);
|
glStencilMask(0xFF);
|
||||||
// glClear(GL_STENCIL_BUFFER_BIT);
|
|
||||||
|
|
||||||
// clear stencilbuffer (tile region)
|
|
||||||
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
|
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
|
||||||
|
|
||||||
if (first) {
|
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);
|
GLES20.glDepthMask(true);
|
||||||
|
|
||||||
// to prevent overdraw gl_less restricts
|
// to prevent overdraw gl_less restricts
|
||||||
// the clip to the area where no other
|
// the clip to the area where no other
|
||||||
// tile was drawn
|
// tile was drawn
|
||||||
@ -197,6 +213,7 @@ class PolygonRenderer {
|
|||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
first = false;
|
first = false;
|
||||||
|
// dont modify depth buffer
|
||||||
GLES20.glDepthMask(false);
|
GLES20.glDepthMask(false);
|
||||||
// only draw to this tile
|
// only draw to this tile
|
||||||
GLES20.glDepthFunc(GLES20.GL_EQUAL);
|
GLES20.glDepthFunc(GLES20.GL_EQUAL);
|
||||||
@ -205,29 +222,50 @@ class PolygonRenderer {
|
|||||||
// stencil op for stencil method polygon drawing
|
// stencil op for stencil method polygon drawing
|
||||||
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
|
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
|
// no need for depth test while drawing stencil
|
||||||
glDisable(GLES20.GL_DEPTH_TEST);
|
glDisable(GLES20.GL_DEPTH_TEST);
|
||||||
}
|
}
|
||||||
mFillPolys[cnt] = l;
|
|
||||||
|
mFillPolys[mCount] = l;
|
||||||
|
|
||||||
// set stencil mask to draw to
|
// set stencil mask to draw to
|
||||||
glStencilMask(1 << cnt++);
|
glStencilMask(1 << mCount++);
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLE_FAN, l.offset, l.verticesCnt);
|
glDrawArrays(GL_TRIANGLE_FAN, l.offset, l.verticesCnt);
|
||||||
|
|
||||||
// draw up to 8 layers into stencil buffer
|
// draw up to 8 layers into stencil buffer
|
||||||
if (cnt == STENCIL_BITS) {
|
if (mCount == STENCIL_BITS) {
|
||||||
fillPolygons(cnt, zoom, scale);
|
fillPolygons(zoom, scale);
|
||||||
cnt = 0;
|
mCount = 0;
|
||||||
|
mStart = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cnt > 0)
|
if (mCount > 0)
|
||||||
fillPolygons(cnt, zoom, scale);
|
fillPolygons(zoom, scale);
|
||||||
|
|
||||||
|
//
|
||||||
|
// if (mCount > 5){
|
||||||
|
// mCount = 0;
|
||||||
|
// mStart = 0;
|
||||||
|
// }
|
||||||
|
|
||||||
glDisable(GL_STENCIL_TEST);
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
if (clip && first)
|
if (first)
|
||||||
drawDepthClip();
|
drawDepthClip();
|
||||||
|
|
||||||
GLES20.glDisableVertexAttribArray(hPolygonVertexPosition);
|
GLES20.glDisableVertexAttribArray(hPolygonVertexPosition);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user