- improve tile locking (use ref counter instead of boolean)

- flip over date line (inserting placeholder tiles in renderer)
- make view coordinates consistent with tile coordinates (flip on y-axis)
This commit is contained in:
Hannes Janetzek 2012-09-30 20:42:04 +02:00
parent 5bf9deef89
commit b4dd83fc09
19 changed files with 854 additions and 2584 deletions

View File

@ -45,13 +45,15 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
/** /**
* A map application which uses the features from the mapsforge map library. The map can be centered to the current * A map application which uses the features from the mapsforge map library. The
* location. A simple file browser for selecting the map file is also included. Some preferences can be adjusted via the * map can be centered to the current location. A simple file browser for
* {@link EditPreferences} activity. * selecting the map file is also included. Some preferences can be adjusted via
* the {@link EditPreferences} activity.
*/ */
public class TileMap extends MapActivity { public class TileMap extends MapActivity {
// implements ActionBar.OnNavigationListener { // implements ActionBar.OnNavigationListener {
// private static final String BUNDLE_CENTER_AT_FIRST_FIX = "centerAtFirstFix"; // private static final String BUNDLE_CENTER_AT_FIRST_FIX =
// "centerAtFirstFix";
private static final String BUNDLE_SHOW_MY_LOCATION = "showMyLocation"; private static final String BUNDLE_SHOW_MY_LOCATION = "showMyLocation";
private static final String BUNDLE_SNAP_TO_LOCATION = "snapToLocation"; private static final String BUNDLE_SNAP_TO_LOCATION = "snapToLocation";
private static final int DIALOG_ENTER_COORDINATES = 0; private static final int DIALOG_ENTER_COORDINATES = 0;
@ -408,7 +410,8 @@ public class TileMap extends MapActivity {
editText.setText(Double.toString(mapCenter.getLongitude())); editText.setText(Double.toString(mapCenter.getLongitude()));
SeekBar zoomlevel = (SeekBar) dialog.findViewById(R.id.zoomLevel); SeekBar zoomlevel = (SeekBar) dialog.findViewById(R.id.zoomLevel);
zoomlevel.setMax(20); // FIXME mMapView.getMapGenerator().getZoomLevelMax()); zoomlevel.setMax(20); // FIXME
// mMapView.getMapGenerator().getZoomLevelMax());
zoomlevel.setProgress(mMapView.getMapPosition().getZoomLevel()); zoomlevel.setProgress(mMapView.getMapPosition().getZoomLevel());
final TextView textView = (TextView) dialog.findViewById(R.id.zoomlevelValue); final TextView textView = (TextView) dialog.findViewById(R.id.zoomlevelValue);
@ -417,34 +420,42 @@ public class TileMap extends MapActivity {
// } else if (id == DIALOG_INFO_MAP_FILE) { // } else if (id == DIALOG_INFO_MAP_FILE) {
// MapInfo mapInfo = mMapView.getMapDatabase().getMapInfo(); // MapInfo mapInfo = mMapView.getMapDatabase().getMapInfo();
// //
// TextView textView = (TextView) dialog.findViewById(R.id.infoMapFileViewName); // TextView textView = (TextView)
// dialog.findViewById(R.id.infoMapFileViewName);
// textView.setText(mMapView.getMapFile()); // textView.setText(mMapView.getMapFile());
// //
// textView = (TextView) dialog.findViewById(R.id.infoMapFileViewSize); // textView = (TextView)
// dialog.findViewById(R.id.infoMapFileViewSize);
// textView.setText(FileUtils.formatFileSize(mapInfo.fileSize, // textView.setText(FileUtils.formatFileSize(mapInfo.fileSize,
// getResources())); // getResources()));
// //
// textView = (TextView) dialog.findViewById(R.id.infoMapFileViewVersion); // textView = (TextView)
// dialog.findViewById(R.id.infoMapFileViewVersion);
// textView.setText(String.valueOf(mapInfo.fileVersion)); // textView.setText(String.valueOf(mapInfo.fileVersion));
// //
// // textView = (TextView) dialog.findViewById(R.id.infoMapFileViewDebug); // // textView = (TextView)
// dialog.findViewById(R.id.infoMapFileViewDebug);
// // if (mapFileInfo.debugFile) { // // if (mapFileInfo.debugFile) {
// // textView.setText(R.string.info_map_file_debug_yes); // // textView.setText(R.string.info_map_file_debug_yes);
// // } else { // // } else {
// // textView.setText(R.string.info_map_file_debug_no); // // textView.setText(R.string.info_map_file_debug_no);
// // } // // }
// //
// textView = (TextView) dialog.findViewById(R.id.infoMapFileViewDate); // textView = (TextView)
// dialog.findViewById(R.id.infoMapFileViewDate);
// Date date = new Date(mapInfo.mapDate); // Date date = new Date(mapInfo.mapDate);
// textView.setText(DateFormat.getDateTimeInstance().format(date)); // textView.setText(DateFormat.getDateTimeInstance().format(date));
// //
// textView = (TextView) dialog.findViewById(R.id.infoMapFileViewArea); // textView = (TextView)
// dialog.findViewById(R.id.infoMapFileViewArea);
// BoundingBox boundingBox = mapInfo.boundingBox; // BoundingBox boundingBox = mapInfo.boundingBox;
// textView.setText(boundingBox.getMinLatitude() + ", " // textView.setText(boundingBox.getMinLatitude() + ", "
// + boundingBox.getMinLongitude() + " - \n" // + boundingBox.getMinLongitude() + " - \n"
// + boundingBox.getMaxLatitude() + ", " + boundingBox.getMaxLongitude()); // + boundingBox.getMaxLatitude() + ", " +
// boundingBox.getMaxLongitude());
// //
// textView = (TextView) dialog.findViewById(R.id.infoMapFileViewStartPosition); // textView = (TextView)
// dialog.findViewById(R.id.infoMapFileViewStartPosition);
// GeoPoint startPosition = mapInfo.startPosition; // GeoPoint startPosition = mapInfo.startPosition;
// if (startPosition == null) { // if (startPosition == null) {
// textView.setText(null); // textView.setText(null);
@ -453,7 +464,8 @@ public class TileMap extends MapActivity {
// + startPosition.getLongitude()); // + startPosition.getLongitude());
// } // }
// //
// textView = (TextView) dialog.findViewById(R.id.infoMapFileViewStartZoomLevel); // textView = (TextView)
// dialog.findViewById(R.id.infoMapFileViewStartZoomLevel);
// Byte startZoomLevel = mapInfo.startZoomLevel; // Byte startZoomLevel = mapInfo.startZoomLevel;
// if (startZoomLevel == null) { // if (startZoomLevel == null) {
// textView.setText(null); // textView.setText(null);
@ -465,10 +477,12 @@ public class TileMap extends MapActivity {
// .findViewById(R.id.infoMapFileViewLanguagePreference); // .findViewById(R.id.infoMapFileViewLanguagePreference);
// textView.setText(mapInfo.languagePreference); // textView.setText(mapInfo.languagePreference);
// //
// textView = (TextView) dialog.findViewById(R.id.infoMapFileViewComment); // textView = (TextView)
// dialog.findViewById(R.id.infoMapFileViewComment);
// textView.setText(mapInfo.comment); // textView.setText(mapInfo.comment);
// //
// textView = (TextView) dialog.findViewById(R.id.infoMapFileViewCreatedBy); // textView = (TextView)
// dialog.findViewById(R.id.infoMapFileViewCreatedBy);
// textView.setText(mapInfo.createdBy); // textView.setText(mapInfo.createdBy);
} else { } else {
super.onPrepareDialog(id, dialog); super.onPrepareDialog(id, dialog);
@ -483,13 +497,17 @@ public class TileMap extends MapActivity {
.getDefaultSharedPreferences(this); .getDefaultSharedPreferences(this);
// MapScaleBar mapScaleBar = mapView.getMapScaleBar(); // MapScaleBar mapScaleBar = mapView.getMapScaleBar();
// mapScaleBar.setShowMapScaleBar(preferences.getBoolean("showScaleBar", false)); // mapScaleBar.setShowMapScaleBar(preferences.getBoolean("showScaleBar",
// String scaleBarUnitDefault = getString(R.string.preferences_scale_bar_unit_default); // false));
// String scaleBarUnit = preferences.getString("scaleBarUnit", scaleBarUnitDefault); // String scaleBarUnitDefault =
// getString(R.string.preferences_scale_bar_unit_default);
// String scaleBarUnit = preferences.getString("scaleBarUnit",
// scaleBarUnitDefault);
// mapScaleBar.setImperialUnits(scaleBarUnit.equals("imperial")); // mapScaleBar.setImperialUnits(scaleBarUnit.equals("imperial"));
// if (preferences.contains("mapGenerator")) { // if (preferences.contains("mapGenerator")) {
// String name = preferences.getString("mapGenerator", MapGeneratorInternal.SW_RENDERER.name()); // String name = preferences.getString("mapGenerator",
// MapGeneratorInternal.SW_RENDERER.name());
// MapGeneratorInternal mapGeneratorInternalNew; // MapGeneratorInternal mapGeneratorInternalNew;
// try { // try {
// mapGeneratorInternalNew = MapGeneratorInternal.valueOf(name); // mapGeneratorInternalNew = MapGeneratorInternal.valueOf(name);
@ -498,7 +516,8 @@ public class TileMap extends MapActivity {
// } // }
// //
// if (mapGeneratorInternalNew != mapGeneratorInternal) { // if (mapGeneratorInternalNew != mapGeneratorInternal) {
// TileGenerator mapGenerator = MapGeneratorFactory.createMapGenerator(mapGeneratorInternalNew); // TileGenerator mapGenerator =
// MapGeneratorFactory.createMapGenerator(mapGeneratorInternalNew);
// mapView.setMapGenerator(mapGenerator); // mapView.setMapGenerator(mapGenerator);
// mapGeneratorInternal = mapGeneratorInternalNew; // mapGeneratorInternal = mapGeneratorInternalNew;
// } // }
@ -525,7 +544,8 @@ public class TileMap extends MapActivity {
} }
// try { // try {
// String textScaleDefault = getString(R.string.preferences_text_scale_default); // String textScaleDefault =
// getString(R.string.preferences_text_scale_default);
// mMapView.setTextScale(Float.parseFloat(preferences.getString("textScale", // mMapView.setTextScale(Float.parseFloat(preferences.getString("textScale",
// textScaleDefault))); // textScaleDefault)));
// } catch (NumberFormatException e) { // } catch (NumberFormatException e) {
@ -596,7 +616,8 @@ public class TileMap extends MapActivity {
} }
/** /**
* Uses the UI thread to display the given text message as toast notification. * Uses the UI thread to display the given text message as toast
* notification.
* *
* @param text * @param text
* the text message to display * the text message to display

View File

@ -65,8 +65,8 @@ public class MapDatabase implements IMapDatabase {
private static final String CACHE_FILE = "%d-%d-%d.tile"; private static final String CACHE_FILE = "%d-%d-%d.tile";
private static final String SERVER_ADDR = "city.informatik.uni-bremen.de"; private static final String SERVER_ADDR = "city.informatik.uni-bremen.de";
private static final String URL = "/osci/map-live/"; // private static final String URL = "/osci/map-live/";
// private static final String URL = "/osci/oscim/"; private static final String URL = "/osci/oscim/";
private final static float REF_TILE_SIZE = 4096.0f; private final static float REF_TILE_SIZE = 4096.0f;

View File

@ -91,10 +91,13 @@ public class MapDatabase implements IMapDatabase {
private static final String CACHE_FILE = "%d-%d-%d.tile"; private static final String CACHE_FILE = "%d-%d-%d.tile";
private static final String SERVER_ADDR = "city.informatik.uni-bremen.de"; private static final String SERVER_ADDR = "city.informatik.uni-bremen.de";
// private static final String URL = "http://city.informatik.uni-bremen.de:8020/test/%d/%d/%d.osmtile"; // private static final String URL =
// "http://city.informatik.uni-bremen.de:8020/test/%d/%d/%d.osmtile";
private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/test/%d/%d/%d.osmtile"; private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/test/%d/%d/%d.osmtile";
// private static final String URL = "http://city.informatik.uni-bremen.de/tiles/tiles.py///test/%d/%d/%d.osmtile"; // private static final String URL =
// private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/gis2/%d/%d/%d.osmtile"; // "http://city.informatik.uni-bremen.de/tiles/tiles.py///test/%d/%d/%d.osmtile";
// private static final String URL =
// "http://city.informatik.uni-bremen.de/osmstache/gis2/%d/%d/%d.osmtile";
private final static float REF_TILE_SIZE = 4096.0f; private final static float REF_TILE_SIZE = 4096.0f;
@ -360,7 +363,7 @@ public class MapDatabase implements IMapDatabase {
return file; return file;
} }
// /////////////// hand sewed tile protocol buffers decoder /////////////////// // /////////////// hand sewed tile protocol buffers decoder ////////////////
private static final int BUFFER_SIZE = 65536; private static final int BUFFER_SIZE = 65536;
private final byte[] mReadBuffer = new byte[BUFFER_SIZE]; private final byte[] mReadBuffer = new byte[BUFFER_SIZE];
@ -604,7 +607,7 @@ public class MapDatabase implements IMapDatabase {
lastY = lat + lastY; lastY = lat + lastY;
mMapGenerator.renderPointOfInterest(layer, mMapGenerator.renderPointOfInterest(layer,
tags, lastY / scale, lastX / scale); tags, Tile.TILE_SIZE - lastY / scale, lastX / scale);
cnt += 2; cnt += 2;
} }
return cnt; return cnt;
@ -800,7 +803,7 @@ public class MapDatabase implements IMapDatabase {
} else { } else {
y = ((result >>> 1) ^ -(result & 1)); y = ((result >>> 1) ^ -(result & 1));
lastY = lastY + y; lastY = lastY + y;
coords[cnt++] = lastY / scale; coords[cnt++] = Tile.TILE_SIZE - lastY / scale;
even = true; even = true;
} }
} }
@ -940,7 +943,8 @@ public class MapDatabase implements IMapDatabase {
return result; return result;
} }
// ///////////////////////// Lightweight HttpClient /////////////////////////////////////// // ///////////////////////// Lightweight HttpClient
// ///////////////////////////////////////
// would have written simple tcp server/client for this... // would have written simple tcp server/client for this...
private int mMaxReq = 0; private int mMaxReq = 0;
@ -1080,7 +1084,8 @@ public class MapDatabase implements IMapDatabase {
len += pos; len += pos;
// this does the same but with a few more allocations: // this does the same but with a few more allocations:
// byte[] request = String.format(REQUEST, Integer.valueOf(tile.zoomLevel), // byte[] request = String.format(REQUEST,
// Integer.valueOf(tile.zoomLevel),
// Integer.valueOf(tile.tileX), Integer.valueOf(tile.tileY)).getBytes(); // Integer.valueOf(tile.tileX), Integer.valueOf(tile.tileY)).getBytes();
try { try {
@ -1138,7 +1143,7 @@ public class MapDatabase implements IMapDatabase {
} }
// //////////////////////////// Tile cache //////////////////////////////////// // //////////////////////////// Tile cache ///////////////////////////////
private boolean cacheRead(Tile tile, File f) { private boolean cacheRead(Tile tile, File f) {
if (f.exists() && f.length() > 0) { if (f.exists() && f.length() > 0) {
@ -1212,7 +1217,10 @@ public class MapDatabase implements IMapDatabase {
mCacheFile = null; mCacheFile = null;
} }
/* All code below is taken from or based on Google's Protocol Buffers implementation: */ /*
* All code below is taken from or based on Google's Protocol Buffers
* implementation:
*/
// Protocol Buffers - Google's data interchange format // Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved. // Copyright 2008 Google Inc. All rights reserved.

View File

@ -38,6 +38,8 @@ public class MapDatabase implements IMapDatabase {
// private Tag[] mTags = { new Tag("boundary", "administrative"), new // private Tag[] mTags = { new Tag("boundary", "administrative"), new
// Tag("admin_level", "2") }; // Tag("admin_level", "2") };
private Tag[] mTags = { new Tag("natural", "water") }; private Tag[] mTags = { new Tag("natural", "water") };
private Tag[] mTagsWay = { new Tag("highway", "primary"), new Tag("name", "Highway Rd") };
private Tag[] mNameTags; private Tag[] mNameTags;
private final MapInfo mMapInfo = private final MapInfo mMapInfo =
@ -50,10 +52,12 @@ public class MapDatabase implements IMapDatabase {
@Override @Override
public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) { public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) {
float lat1 = -0.5f; int size = Tile.TILE_SIZE;
float lon1 = -0.5f;
float lat2 = Tile.TILE_SIZE + 0.5f; float lat1 = -1;
float lon2 = Tile.TILE_SIZE + 0.5f; float lon1 = -1;
float lat2 = size + 1;
float lon2 = size + 1;
mCoords[0] = lon1; mCoords[0] = lon1;
mCoords[1] = lat1; mCoords[1] = lat1;
@ -70,13 +74,13 @@ public class MapDatabase implements IMapDatabase {
mCoords[8] = lon1; mCoords[8] = lon1;
mCoords[9] = lat1; mCoords[9] = lat1;
mIndex[0] = 8; mIndex[0] = 10;
mIndex[1] = 2; mIndex[1] = 0;
lon1 = 40; lon1 = 40;
lon2 = Tile.TILE_SIZE - 40; lon2 = size - 40;
lat1 = 40; lat1 = 40;
lat2 = Tile.TILE_SIZE - 40; lat2 = size - 40;
mCoords[10] = lon1; mCoords[10] = lon1;
mCoords[11] = lat1; mCoords[11] = lat1;
@ -93,19 +97,84 @@ public class MapDatabase implements IMapDatabase {
mCoords[18] = lon1; mCoords[18] = lon1;
mCoords[19] = lat1; mCoords[19] = lat1;
mIndex[2] = 8; mIndex[2] = 10;
mIndex[3] = 2; mIndex[3] = 0;
mapDatabaseCallback.renderWay((byte) 0, mTags, mCoords, mIndex, true); mapDatabaseCallback.renderWay((byte) 0, mTags, mCoords, mIndex, true);
lon1 = Tile.TILE_SIZE / 2; mIndex[0] = 4;
lat1 = Tile.TILE_SIZE / 2; mIndex[1] = -1;
mNameTags = new Tag[2]; // middle horizontal
mNameTags[0] = new Tag("place", "city"); mCoords[0] = 0;
mNameTags[1] = new Tag("name", tile.toString()); mCoords[1] = size / 2;
mapDatabaseCallback.renderPointOfInterest((byte) 0, mNameTags, (int) lat1, mCoords[2] = size;
(int) lon1); mCoords[3] = size / 2;
Tag[] tags = new Tag[2];
tags[0] = mTagsWay[0];
tags[1] = mTagsWay[1];
mapDatabaseCallback.renderWay((byte) 0, tags, mCoords, mIndex, false);
// center up
mCoords[0] = size / 2;
mCoords[1] = -size / 2;
mCoords[2] = size / 2;
mCoords[3] = size / 2;
tags = new Tag[2];
tags[0] = mTagsWay[0];
tags[1] = mTagsWay[1];
mapDatabaseCallback.renderWay((byte) 0, tags, mCoords, mIndex,
false);
// center down
mCoords[0] = size / 2;
mCoords[1] = size / 2;
mCoords[2] = size / 2;
mCoords[3] = size / 2 + size;
tags = new Tag[2];
tags[0] = mTagsWay[0];
tags[1] = mTagsWay[1];
mapDatabaseCallback.renderWay((byte) 0, tags, mCoords, mIndex, false);
// left-top to center
mCoords[0] = size / 2;
mCoords[1] = size / 2;
mCoords[2] = 10;
mCoords[3] = 10;
tags = new Tag[2];
tags[0] = mTagsWay[0];
tags[1] = mTagsWay[1];
mapDatabaseCallback.renderWay((byte) 1, tags, mCoords, mIndex, false);
// middle horizontal
mCoords[0] = 0;
mCoords[1] = 10;
mCoords[2] = size;
mCoords[3] = 10;
tags = new Tag[2];
tags[0] = mTagsWay[0];
tags[1] = mTagsWay[1];
mapDatabaseCallback.renderWay((byte) 1, tags, mCoords, mIndex, false);
// middle horizontal
mCoords[0] = 10;
mCoords[1] = 0;
mCoords[2] = 10;
mCoords[3] = size;
tags = new Tag[2];
tags[0] = mTagsWay[0];
tags[1] = mTagsWay[1];
mapDatabaseCallback.renderWay((byte) 1, tags, mCoords, mIndex, false);
// lon1 = size / 2;
// lat1 = size / 2;
// mNameTags = new Tag[2];
// mNameTags[0] = new Tag("place", "city");
// mNameTags[1] = new Tag("name", tile.toString());
// mapDatabaseCallback.renderPointOfInterest((byte) 0, mNameTags, (int)
// lat1,
// (int) lon1);
return QueryResult.SUCCESS; return QueryResult.SUCCESS;
} }

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,7 @@ public class Compass {
mAngle = event.values[0]; mAngle = event.values[0];
if (mMapView != null) { if (mMapView != null) {
mMapView.getMapPosition().setRotation(mAngle); mMapView.getMapPosition().setRotation(-mAngle);
mMapView.redrawMap(); mMapView.redrawMap();
} }
} }

View File

@ -57,6 +57,8 @@ public class MapView extends FrameLayout {
public static final boolean debugFrameTime = false; public static final boolean debugFrameTime = false;
public static final boolean testRegionZoom = false; public static final boolean testRegionZoom = false;
public static final boolean staticLabeling = true;
private static final boolean debugDatabase = false; private static final boolean debugDatabase = false;
RegionLookup mRegionLookup; RegionLookup mRegionLookup;
@ -82,8 +84,6 @@ 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.

View File

@ -27,9 +27,10 @@ import android.util.Log;
* together with its zoom level. * together with its zoom level.
*/ */
public class MapViewPosition { public class MapViewPosition {
// private static final String TAG = "MapViewPosition"; private static final String TAG = "MapViewPosition";
public final static int MAX_ZOOMLEVEL = 17; public final static int MAX_ZOOMLEVEL = 17;
public final static int MIN_ZOOMLEVEL = 2;
private final static float MAX_ANGLE = 20; private final static float MAX_ANGLE = 20;
@ -68,7 +69,7 @@ public class MapViewPosition {
void setViewport(int width, int height) { void setViewport(int width, int height) {
Matrix.frustumM(mProjMatrix, 0, -0.5f * width, 0.5f * width, Matrix.frustumM(mProjMatrix, 0, -0.5f * width, 0.5f * width,
-0.5f * height, 0.5f * height, 1, 2); 0.5f * height, -0.5f * height, 1, 2);
Matrix.translateM(mProjMatrix, 0, 0, 0, -1); Matrix.translateM(mProjMatrix, 0, 0, 0, -1);
@ -92,14 +93,14 @@ public class MapViewPosition {
// && mapPosition.scale == mScale // && mapPosition.scale == mScale
// && mapPosition.angle == mRotation) // && mapPosition.angle == mRotation)
// return false; // return false;
byte z = mZoomLevel;
mapPosition.lat = mLatitude; mapPosition.lat = mLatitude;
mapPosition.lon = mLongitude; mapPosition.lon = mLongitude;
mapPosition.angle = mRotation; mapPosition.angle = mRotation;
mapPosition.zoomLevel = mZoomLevel;
mapPosition.scale = mScale; mapPosition.scale = mScale;
mapPosition.zoomLevel = z;
byte z = mZoomLevel;
mapPosition.x = MercatorProjection.longitudeToPixelX(mLongitude, z); mapPosition.x = MercatorProjection.longitudeToPixelX(mLongitude, z);
mapPosition.y = MercatorProjection.latitudeToPixelY(mLatitude, z); mapPosition.y = MercatorProjection.latitudeToPixelY(mLatitude, z);
@ -138,13 +139,12 @@ public class MapViewPosition {
if (mv[3] != 0) { if (mv[3] != 0) {
float w = 1 / mv[3]; float w = 1 / mv[3];
float xx = mv[0] * w; coords[position] = mv[0] * w;
float yy = mv[1] * w; coords[position + 1] = mv[1] * w;
} else {
coords[position] = xx;
coords[position + 1] = yy;
}
// else what? // else what?
Log.d(TAG, "... what?");
}
} }
private void updateMatrix() { private void updateMatrix() {
@ -152,7 +152,7 @@ public class MapViewPosition {
// tilt map // tilt map
float tilt = mTilt; float tilt = mTilt;
Matrix.setRotateM(mTmpMatrix, 0, -tilt / (mHeight / 2), 1, 0, 0); Matrix.setRotateM(mTmpMatrix, 0, tilt / (mHeight / 2), 1, 0, 0);
// apply first rotation, then tilt // apply first rotation, then tilt
Matrix.multiplyMM(mRotateMatrix, 0, mTmpMatrix, 0, mRotateMatrix, 0); Matrix.multiplyMM(mRotateMatrix, 0, mTmpMatrix, 0, mRotateMatrix, 0);
@ -177,10 +177,10 @@ public class MapViewPosition {
float tilt = FloatMath.sin((float) Math.toRadians(mTilt)) * 4; float tilt = FloatMath.sin((float) Math.toRadians(mTilt)) * 4;
unproject(-1, 1, tilt, mBBoxCoords, 0); // top-left unproject(-1, 1, -tilt, mBBoxCoords, 0); // top-left
unproject(1, 1, tilt, mBBoxCoords, 2); // top-right unproject(1, 1, -tilt, mBBoxCoords, 2); // top-right
unproject(1, -1, -tilt, mBBoxCoords, 4); // bottom-right unproject(1, -1, tilt, mBBoxCoords, 4); // bottom-right
unproject(-1, -1, -tilt, mBBoxCoords, 6); // bottom-left unproject(-1, -1, tilt, mBBoxCoords, 6); // bottom-left
byte z = mZoomLevel; byte z = mZoomLevel;
double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, z); double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, z);
@ -333,8 +333,8 @@ public class MapViewPosition {
if (mMapView.enableRotation || mMapView.enableCompass) { if (mMapView.enableRotation || mMapView.enableCompass) {
double rad = Math.toRadians(mRotation); double rad = Math.toRadians(mRotation);
double x = dx * Math.cos(rad) + dy * -Math.sin(rad); double x = dx * Math.cos(rad) + dy * Math.sin(rad);
double y = dx * Math.sin(rad) + dy * Math.cos(rad); double y = dx * -Math.sin(rad) + dy * Math.cos(rad);
dx = x; dx = x;
dy = y; dy = y;
} }
@ -357,7 +357,7 @@ public class MapViewPosition {
moveMap(cx, cy); moveMap(cx, cy);
// Log.d("MapViewPosition", "rotate:" + angle + " " + (mRotation - // Log.d("MapViewPosition", "rotate:" + angle + " " + (mRotation -
// angle)); // angle));
mRotation -= angle; mRotation += angle;
updateMatrix(); updateMatrix();
} }
@ -426,12 +426,13 @@ public class MapViewPosition {
int z = FastMath.log2((int) newScale); int z = FastMath.log2((int) newScale);
if (z <= 0 || (z >= MAX_ZOOMLEVEL && mScale >= 8)) if (z < MIN_ZOOMLEVEL || (z >= MAX_ZOOMLEVEL && mScale >= 8))
return false; return false;
if (z > MAX_ZOOMLEVEL) { if (z > MAX_ZOOMLEVEL) {
// z16 shows everything, just increase scaling // z17 shows everything, just increase scaling
if (mScale * scale > 8) // need to fix this for ScanBox
if (mScale * scale > 2) // 8)
return false; return false;
mScale *= scale; mScale *= scale;

View File

@ -1,35 +0,0 @@
/*
* 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.overlay;
public class Overlay {
synchronized void move() {
}
synchronized void addBitmap() {
}
synchronized boolean onTouch() {
return true;
}
synchronized void draw() {
}
}

View File

@ -1,19 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* 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.overlay;
public class TiledOverlay extends Overlay {
}

View File

@ -21,7 +21,6 @@ import static android.opengl.GLES20.GL_DYNAMIC_DRAW;
import static android.opengl.GLES20.GL_ONE; 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_POLYGON_OFFSET_FILL;
import static android.opengl.GLES20.GL_STENCIL_BUFFER_BIT;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
@ -63,7 +62,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private final MapView mMapView; private final MapView mMapView;
private final MapViewPosition mMapViewPosition; private final MapViewPosition mMapViewPosition;
private static final MapPosition mMapPosition = new MapPosition(); private static MapPosition mMapPosition;
private static ArrayList<VertexBufferObject> mVBOs; private static ArrayList<VertexBufferObject> mVBOs;
@ -82,7 +81,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// mNextTiles is set by TileLoader and swapped with // mNextTiles is set by TileLoader and swapped with
// mDrawTiles in onDrawFrame in GL thread. // mDrawTiles in onDrawFrame in GL thread.
private static TilesData mNextTiles, mDrawTiles; private static TilesData mNextTiles;
/* package */static TilesData mDrawTiles;
// flag set by updateVisibleList when current visible tiles // flag set by updateVisibleList when current visible tiles
// changed. used in onDrawFrame to flip mNextTiles/mDrawTiles // changed. used in onDrawFrame to flip mNextTiles/mDrawTiles
@ -95,9 +95,78 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private static boolean mUpdateColor = false; private static boolean mUpdateColor = false;
// lock to synchronize Main- and GL-Thread // drawlock to synchronize Main- and GL-Thread
static ReentrantLock tilelock = new ReentrantLock(); static ReentrantLock tilelock = new ReentrantLock();
static ReentrantLock lock = new ReentrantLock(); static ReentrantLock drawlock = new ReentrantLock();
/* package */static int mHolderCount;
// scanline fill class used to check tile visibility
private static ScanBox mScanBox = new ScanBox() {
@Override
void setVisible(int y, int x1, int x2) {
int cnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles;
for (int i = 0; i < cnt; i++) {
MapTile t = tiles[i];
if (t.tileY == y && t.tileX >= x1 && t.tileX < x2)
t.isVisible = true;
}
int xmax = 1 << mZoom;
if (x1 >= 0 && x2 < xmax)
return;
// add placeholder tiles to show both sides
// of date line...
for (int x = x1; x < x2; x++) {
MapTile holder = null;
MapTile tile = null;
boolean found = false;
int xx = x;
if (x >= 0 && x < xmax)
continue;
if (x < 0)
xx = xmax + x;
else
xx = x - xmax;
if (xx < 0 || xx >= xmax)
continue;
for (int i = cnt; i < cnt + mHolderCount; i++)
if (tiles[i].tileX == x && tiles[i].tileY == y) {
found = true;
break;
}
if (found)
continue;
for (int i = 0; i < cnt; i++)
if (tiles[i].tileX == xx && tiles[i].tileY == y) {
tile = tiles[i];
break;
}
if (tile == null)
continue;
// Log.d(TAG, "add placeholder " + y + " " + x + ">>" + xx + " "
// + tile);
holder = new MapTile(x, y, mZoom);
holder.isVisible = true;
holder.holder = tile;
tiles[cnt + mHolderCount++] = holder;
}
}
};
/** /**
* @param mapView * @param mapView
@ -108,8 +177,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mMapView = mapView; mMapView = mapView;
mMapViewPosition = mapView.getMapViewPosition(); mMapViewPosition = mapView.getMapViewPosition();
// mMapPosition = new MapPosition(); mMapPosition = new MapPosition();
mMapPosition.init(); mMapPosition.init();
Matrix.setIdentityM(mMVPMatrix, 0); Matrix.setIdentityM(mMVPMatrix, 0);
@ -141,63 +209,38 @@ public class GLRenderer implements GLSurfaceView.Renderer {
} }
/** /**
* called by TileLoader when list of active tiles changed * Called by TileLoader when list of active tiles changed. the list is
* copied to mNextTiles to be used in next call to onDrawFrame
* *
* @param tiles * @param tiles
* active tiles * active tiles
* @return mNextTiles (the previously active tiles)
*/ */
static TilesData updateTiles(TilesData tiles) { static void updateTiles(TilesData tiles) {
GLRenderer.tilelock.lock();
// unlock previously active tiles MapTile[] newTiles = tiles.tiles;
for (int i = 0; i < mNextTiles.cnt; i++) {
MapTile t = mNextTiles.tiles[i];
boolean found = false;
for (int j = 0; j < tiles.cnt; j++) {
if (tiles.tiles[j] == t) {
found = true;
break;
}
}
if (found)
continue;
for (int j = 0; j < mDrawTiles.cnt; j++) {
if (mDrawTiles.tiles[j] == t) {
found = true;
break;
}
}
if (found)
continue;
t.unlock();
}
TilesData tmp = mNextTiles;
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 < mNextTiles.cnt; i++) { for (int i = 0, n = tiles.cnt; i < n; i++)
MapTile t = mNextTiles.tiles[i]; newTiles[i].lock();
if (!t.isLocked)
t.lock();
}
for (int j = 0; j < mDrawTiles.cnt; j++) { // dont flip next/drawTiles while copying
MapTile t = mDrawTiles.tiles[j]; GLRenderer.tilelock.lock();
if (!t.isLocked)
t.lock();
}
// GLThread flips mNextTiles with mDrawTiles MapTile[] nextTiles = mNextTiles.tiles;
// unlock previously active tiles
for (int i = 0, n = mNextTiles.cnt; i < n; i++)
nextTiles[i].unlock();
// copy newTiles to nextTiles
System.arraycopy(newTiles, 0, nextTiles, 0, tiles.cnt);
mNextTiles.cnt = tiles.cnt;
// flip next/drawTiles in next onDrawFrame
mUpdateTiles = true; mUpdateTiles = true;
GLRenderer.tilelock.unlock(); GLRenderer.tilelock.unlock();
return tmp;
} }
/** /**
@ -267,7 +310,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// add fill coordinates // add fill coordinates
newSize += 8; newSize += 8;
// FIXME probably not a good idea to do this in gl thread... // probably not a good idea to do this in gl thread...
if (sbuf.capacity() < newSize) { if (sbuf.capacity() < newSize) {
ByteBuffer bbuf = ByteBuffer.allocateDirect(newSize * SHORT_BYTES) ByteBuffer bbuf = ByteBuffer.allocateDirect(newSize * SHORT_BYTES)
.order(ByteOrder.nativeOrder()); .order(ByteOrder.nativeOrder());
@ -317,7 +360,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
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;
@ -385,68 +427,26 @@ public class GLRenderer implements GLSurfaceView.Renderer {
CACHE_TILES -= 50; CACHE_TILES -= 50;
} }
private static boolean isVisible(MapTile tile) {
float dx, dy, scale, div = 1;
MapPosition mapPosition = mMapPosition;
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;
ssize += Tile.TILE_SIZE;
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;
private static void setMatrix(float[] matrix, MapTile tile, private static void setMatrix(float[] matrix, MapTile tile,
float div, boolean project) { float div, boolean project) {
float x, y, scale;
MapPosition mapPosition = mMapPosition; MapPosition mapPosition = mMapPosition;
scale = mapPosition.scale / (div * COORD_MULTIPLIER); float x = (float) (tile.pixelX - mapPosition.x * div);
x = (float) (tile.pixelX - mapPosition.x * div); float y = (float) (tile.pixelY - mapPosition.y * div);
y = (float) (tile.pixelY - mapPosition.y * div); float scale = mapPosition.scale / div;
Matrix.setIdentityM(matrix, 0); Matrix.setIdentityM(matrix, 0);
// scale to tile to world coordinates
Matrix.scaleM(matrix, 0, scale, scale, 1);
// translate relative to map center // translate relative to map center
Matrix.translateM(matrix, 0, x * COORD_MULTIPLIER, matrix[12] = x * scale;
-(y + Tile.TILE_SIZE) * COORD_MULTIPLIER, 0); matrix[13] = y * scale;
// scale to tile to world coordinates
scale /= COORD_MULTIPLIER;
matrix[0] = scale;
matrix[5] = scale;
if (mRotate) if (mRotate)
Matrix.multiplyMM(matrix, 0, mapPosition.rotation, 0, matrix, 0); Matrix.multiplyMM(matrix, 0, mapPosition.rotation, 0, matrix, 0);
@ -471,11 +471,17 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// prevent main thread recreating all tiles (updateMap) // prevent main thread recreating all tiles (updateMap)
// while rendering is going. not have seen this happen // while rendering is going. not have seen this happen
// yet though // yet though
GLRenderer.lock.lock(); GLRenderer.drawlock.lock();
if (MapView.debugFrameTime) if (MapView.debugFrameTime)
start = SystemClock.uptimeMillis(); start = SystemClock.uptimeMillis();
if (mUpdateColor) {
float cc[] = mClearColor;
GLES20.glClearColor(cc[0], cc[1], cc[2], cc[3]);
mUpdateColor = false;
}
// Note: it seems faster to also clear the stencil buffer even // Note: it seems faster to also clear the stencil buffer even
// when not needed. probaly otherwise it is masked out from the // when not needed. probaly otherwise it is masked out from the
// depth buffer as they share the same memory region afaik // depth buffer as they share the same memory region afaik
@ -496,14 +502,17 @@ public class GLRenderer implements GLSurfaceView.Renderer {
} }
if (mDrawTiles == null || mDrawTiles.cnt == 0) { if (mDrawTiles == null || mDrawTiles.cnt == 0) {
GLRenderer.lock.unlock(); GLRenderer.drawlock.unlock();
return; return;
} }
mRotate = mMapView.enableRotation || mMapView.enableCompass;
// get current MapPosition, set mTileCoords (mapping of screen to model // get current MapPosition, set mTileCoords (mapping of screen to model
// coordinates) // coordinates)
MapPosition mapPosition = mMapPosition; MapPosition mapPosition = mMapPosition;
boolean changed = mMapViewPosition.getMapPosition(mapPosition, mTileCoords); float[] coords = mTileCoords;
boolean changed = mMapViewPosition.getMapPosition(mapPosition, coords);
int tileCnt = mDrawTiles.cnt; int tileCnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles; MapTile[] tiles = mDrawTiles.tiles;
@ -517,29 +526,19 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// zoom-level changed. // zoom-level changed.
float div = scaleDiv(tiles[0]); float div = scaleDiv(tiles[0]);
mRotate = mMapView.enableRotation || mMapView.enableCompass;
float s = Tile.TILE_SIZE; float s = Tile.TILE_SIZE;
float scale = mapPosition.scale / div; float scale = mapPosition.scale / div;
float px = (float) (mapPosition.x * div); double px = mapPosition.x * div;
float py = (float) (mapPosition.y * div); double py = mapPosition.y * div;
mTileCoords[0] = (px + mTileCoords[0] / scale) / s; for (int i = 0; i < 8; i += 2) {
mTileCoords[1] = (py - mTileCoords[1] / scale) / s; coords[i + 0] = (float) ((px + coords[i + 0] / scale) / s);
mTileCoords[2] = (px + mTileCoords[2] / scale) / s; coords[i + 1] = (float) ((py + coords[i + 1] / scale) / s);
mTileCoords[3] = (py - mTileCoords[3] / scale) / s;
mTileCoords[4] = (px + mTileCoords[4] / scale) / s;
mTileCoords[5] = (py - mTileCoords[5] / scale) / s;
mTileCoords[6] = (px + mTileCoords[6] / scale) / s;
mTileCoords[7] = (py - mTileCoords[7] / scale) / s;
byte z = tiles[0].zoomLevel;
ScanBox.scan(mTileCoords, mDrawTiles, 1 << z);
} }
if (mUpdateColor && mClearColor != null) { mHolderCount = 0;
GLES20.glClearColor(mClearColor[0], mClearColor[1], mClearColor[2], mClearColor[3]); mScanBox.scan(coords, tiles[0].zoomLevel);
mUpdateColor = false; tileCnt += mHolderCount;
} }
uploadCnt = 0; uploadCnt = 0;
@ -554,15 +553,21 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (!tile.isVisible) if (!tile.isVisible)
continue; continue;
if (MapView.staticLabeling) {
if (tile.texture == null && TextRenderer.drawToTexture(tile)) if (tile.texture == null && TextRenderer.drawToTexture(tile))
updateTextures++; updateTextures++;
}
if (tile.newData) { if (tile.newData) {
uploadTileData(tile); uploadTileData(tile);
continue; continue;
} }
if (tile.holder != null) {
if (!tile.isReady) { if (tile.holder.newData) {
uploadTileData(tile.holder);
}
tile.isReady = tile.holder.isReady;
} else if (!tile.isReady) {
// check near relatives if they can serve as proxy // check near relatives if they can serve as proxy
MapTile rel = tile.rel.parent.tile; MapTile rel = tile.rel.parent.tile;
if (rel != null && rel.newData) { if (rel != null && rel.newData) {
@ -583,22 +588,26 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (uploadCnt > 0) if (uploadCnt > 0)
checkBufferUsage(); checkBufferUsage();
if (MapView.staticLabeling) {
if (updateTextures > 0) if (updateTextures > 0)
TextRenderer.compileTextures(); TextRenderer.compileTextures();
}
GLES20.glEnable(GL_DEPTH_TEST); GLES20.glEnable(GL_DEPTH_TEST);
GLES20.glEnable(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) MapTile t = tiles[i];
drawTile(tiles[i]); if (t.isVisible && t.isReady)
drawTile(t);
} }
// 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. TODO draw all parent before grandparent // buffer. 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) MapTile t = tiles[i];
drawProxyTile(tiles[i]); if (t.isVisible && !t.isReady && (t.holder == null))
drawProxyTile(t);
} }
// GlUtils.checkGlError("end draw"); // GlUtils.checkGlError("end draw");
@ -608,6 +617,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mDrawCount = 0; mDrawCount = 0;
mDrawSerial++; mDrawSerial++;
if (MapView.staticLabeling) {
GLES20.glEnable(GL_BLEND); GLES20.glEnable(GL_BLEND);
int z = mapPosition.zoomLevel; int z = mapPosition.zoomLevel;
float s = mapPosition.scale; float s = mapPosition.scale;
@ -618,46 +628,41 @@ public class GLRenderer implements GLSurfaceView.Renderer {
scale = 1; scale = 1;
if (z >= TileGenerator.STROKE_MAX_ZOOM_LEVEL) if (z >= TileGenerator.STROKE_MAX_ZOOM_LEVEL)
TextRenderer.beginDraw(FloatMath.sqrt(s) / scale, mProjMatrix); TextRenderer.beginDraw(scale / FloatMath.sqrt(s), mProjMatrix);
else else
TextRenderer.beginDraw(s, mProjMatrix); TextRenderer.beginDraw(1 / s, mProjMatrix);
for (int i = 0; i < tileCnt; i++) { for (int i = 0; i < tileCnt; i++) {
if (!tiles[i].isVisible || tiles[i].texture == null) MapTile t = tiles[i];
if (!t.isVisible)
continue; continue;
setMatrix(mMVPMatrix, tiles[i], 1, false); if (t.holder == null) {
TextRenderer.drawTile(tiles[i], mMVPMatrix); if (t.texture != null) {
setMatrix(mMVPMatrix, t, 1, false);
TextRenderer.drawTile(t, mMVPMatrix);
}
} else {
if (t.holder.texture != null) {
setMatrix(mMVPMatrix, t, 1, false);
TextRenderer.drawTile(t.holder, mMVPMatrix);
}
}
} }
TextRenderer.endDraw(); TextRenderer.endDraw();
}
// TODO call overlay renderer here // TODO call overlay renderer here
// s = 0.5f;
// mTileCoords[0] = -s;
// mTileCoords[1] = s;
// mTileCoords[2] = s;
// mTileCoords[3] = s;
// mTileCoords[4] = -s;
// mTileCoords[5] = -s;
// mTileCoords[6] = s;
// mTileCoords[7] = -s;
//
// Matrix.setIdentityM(mMVPMatrix, 0);
// // Matrix.scaleM(mMVPMatrix, 0, 0.99f, 0.99f, 1);
// // Matrix.multiplyMM(mMVPMatrix, 0, mRotateMatrix, 0, mMVPMatrix, 0);
// // Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
// PolygonRenderer.debugDraw(mMVPMatrix, mTileCoords);
if (MapView.debugFrameTime) { if (MapView.debugFrameTime) {
GLES20.glFinish(); GLES20.glFinish();
Log.d(TAG, "draw took " + (SystemClock.uptimeMillis() - start)); Log.d(TAG, "draw took " + (SystemClock.uptimeMillis() - start));
} }
GLRenderer.lock.unlock(); GLRenderer.drawlock.unlock();
} }
// 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 int mDrawSerial = 0;
private static void drawTile(MapTile tile) { private static void drawTile(MapTile tile) {
// draw parents only once // draw parents only once
@ -665,15 +670,16 @@ public class GLRenderer implements GLSurfaceView.Renderer {
return; return;
float div = scaleDiv(tile); float div = scaleDiv(tile);
float[] mvp = mMVPMatrix;
MapPosition pos = mMapPosition;
tile.lastDraw = mDrawSerial; tile.lastDraw = mDrawSerial;
int z = mMapPosition.zoomLevel;
float s = mMapPosition.scale;
float[] mvp = mMVPMatrix;
setMatrix(mvp, tile, div, true); setMatrix(mvp, tile, div, true);
if (tile.holder != null)
tile = tile.holder;
GLES20.glPolygonOffset(0, mDrawCount++); GLES20.glPolygonOffset(0, mDrawCount++);
GLES20.glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id); GLES20.glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id);
@ -696,21 +702,22 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (pl != null && pnext < lnext) { if (pl != null && pnext < lnext) {
GLES20.glDisable(GL_BLEND); GLES20.glDisable(GL_BLEND);
pl = PolygonRenderer.drawPolygons(pl, lnext, mvp, z, s, !clipped); pl = PolygonRenderer.drawPolygons(pos, pl, lnext, mvp, !clipped);
clipped = true; clipped = true;
} else { } else {
// FIXME // FIXME
if (!clipped) { if (!clipped) {
PolygonRenderer.drawPolygons(null, 0, mvp, z, s, true); PolygonRenderer.drawPolygons(pos, null, 0, mvp, true);
clipped = true; clipped = true;
} }
GLES20.glEnable(GL_BLEND); GLES20.glEnable(GL_BLEND);
ll = LineRenderer.drawLines(tile, ll, pnext, mvp, div, z, s, simpleShader); ll = LineRenderer.drawLines(pos, ll, pnext, mvp, div,
simpleShader, tile.lineOffset);
} }
} }
} }
// TODO could use tile.proxies here // TODO should check tile.proxies here
private static boolean drawProxyChild(MapTile tile) { private static boolean drawProxyChild(MapTile tile) {
int drawn = 0; int drawn = 0;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
@ -721,10 +728,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (c == null) if (c == null)
continue; continue;
if (!isVisible(c)) { // if (!isVisible(c)) {
drawn++; // drawn++;
continue; // continue;
} // }
if (c.isReady) { if (c.isReady) {
drawTile(c); drawTile(c);
@ -789,10 +796,11 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mHeight = height; mHeight = height;
float s = 0.5f; float s = 0.5f;
// use this to scale only the view to see which tiles are rendered // use this to scale only the view to see better which tiles are
// rendered
// s = 1.0f; // s = 1.0f;
Matrix.frustumM(mProjMatrix, 0, -s * width, s * width, Matrix.frustumM(mProjMatrix, 0, -s * width, s * width,
-s * height, s * height, 1, 2); s * height, -s * height, 1, 2);
Matrix.translateM(mProjMatrix, 0, 0, 0, -1); Matrix.translateM(mProjMatrix, 0, 0, 0, -1);
// set to zero: we modify the z value with polygon-offset for clipping // set to zero: we modify the z value with polygon-offset for clipping
@ -805,7 +813,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mMapView.redrawMap(); mMapView.redrawMap();
return; return;
} }
mNewSurface = false; mNewSurface = false;
mBufferMemoryUsage = 0; mBufferMemoryUsage = 0;
@ -827,17 +834,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// Set up textures // Set up textures
TextRenderer.setup(numTiles); TextRenderer.setup(numTiles);
if (mClearColor != null) { if (mClearColor != null)
GLES20.glClearColor(mClearColor[0], mClearColor[1], mUpdateColor = true;
mClearColor[2], mClearColor[3]);
} else {
GLES20.glClearColor(0.98f, 0.98f, 0.97f, 1.0f);
}
GlUtils.checkGlError("onSurfaceChanged");
GLES20.glClear(GL_STENCIL_BUFFER_BIT);
// FIXME this should be synchronized
mMapView.redrawMap(); mMapView.redrawMap();
} }
@ -858,6 +858,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
TextRenderer.init(); TextRenderer.init();
mNewSurface = true; mNewSurface = true;
// mUpdateColor = true;
// glEnable(GL_SCISSOR_TEST); // glEnable(GL_SCISSOR_TEST);
// glScissor(0, 0, mWidth, mHeight); // glScissor(0, 0, mWidth, mHeight);
@ -870,3 +871,46 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private boolean mNewSurface; private boolean mNewSurface;
} }
//
// private static boolean isVisible(MapTile tile) {
// float dx, dy, scale, div = 1;
// MapPosition mapPosition = mMapPosition;
// 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;
// ssize += Tile.TILE_SIZE;
// 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;
// }

View File

@ -18,6 +18,7 @@ import java.nio.ShortBuffer;
import org.oscim.theme.renderinstruction.Line; import org.oscim.theme.renderinstruction.Line;
import org.oscim.utils.GlUtils; import org.oscim.utils.GlUtils;
import org.oscim.view.MapPosition;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.util.FloatMath; import android.util.FloatMath;
@ -74,26 +75,25 @@ class LineRenderer {
return true; return true;
} }
// static int mSimple = 1; static LineLayer drawLines(MapPosition pos, LineLayer layer, int next,
float[] matrix, float div, int mode, int bufferOffset) {
static LineLayer drawLines(MapTile tile, LineLayer layer, int next, float[] matrix, int zoom = pos.zoomLevel;
float div, double zoom, float scale, int mode) { float scale = pos.scale;
// int mode = mSimple;
if (layer == null) if (layer == null)
return null; return null;
// TODO should use fast line program when view is not tilted
GLES20.glUseProgram(lineProgram[mode]); GLES20.glUseProgram(lineProgram[mode]);
GLES20.glEnableVertexAttribArray(hLineVertexPosition[mode]); GLES20.glEnableVertexAttribArray(hLineVertexPosition[mode]);
GLES20.glEnableVertexAttribArray(hLineTexturePosition[mode]); GLES20.glEnableVertexAttribArray(hLineTexturePosition[mode]);
GLES20.glVertexAttribPointer(hLineVertexPosition[mode], 2, GLES20.GL_SHORT, GLES20.glVertexAttribPointer(hLineVertexPosition[mode], 2, GLES20.GL_SHORT,
false, 8, tile.lineOffset + LINE_VERTICES_DATA_POS_OFFSET); false, 8, bufferOffset + LINE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(hLineTexturePosition[mode], 2, GLES20.GL_SHORT, GLES20.glVertexAttribPointer(hLineTexturePosition[mode], 2, GLES20.GL_SHORT,
false, 8, tile.lineOffset + LINE_VERTICES_DATA_TEX_OFFSET); false, 8, bufferOffset + LINE_VERTICES_DATA_TEX_OFFSET);
GLES20.glUniformMatrix4fv(hLineMatrix[mode], 1, false, matrix, 0); GLES20.glUniformMatrix4fv(hLineMatrix[mode], 1, false, matrix, 0);

View File

@ -17,13 +17,12 @@ package org.oscim.view.renderer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import org.oscim.core.MercatorProjection;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.database.MapInfo;
import org.oscim.theme.RenderTheme; import org.oscim.theme.RenderTheme;
import org.oscim.utils.GlConfigChooser; import org.oscim.utils.GlConfigChooser;
import org.oscim.view.MapPosition; import org.oscim.view.MapPosition;
import org.oscim.view.MapView; import org.oscim.view.MapView;
import org.oscim.view.MapViewPosition;
import org.oscim.view.generator.JobTile; import org.oscim.view.generator.JobTile;
import android.content.Context; import android.content.Context;
@ -37,9 +36,13 @@ public class MapRenderer extends GLSurfaceView {
private GLRenderer mRenderer; private GLRenderer mRenderer;
private static final int MAX_TILES_IN_QUEUE = 40; private static final int MAX_TILES_IN_QUEUE = 40;
private static final int CACHE_THRESHOLD = 50;
private static MapView mMapView; private static MapView mMapView;
private static final MapPosition mMapPosition = new MapPosition();
private final MapViewPosition mMapViewPosition;
// new jobs for the MapWorkers // new jobs for the MapWorkers
private static ArrayList<JobTile> mJobList; private static ArrayList<JobTile> mJobList;
@ -49,16 +52,21 @@ public class MapRenderer extends GLSurfaceView {
// tiles that have new data to upload, see passTile() // tiles that have new data to upload, see passTile()
private static ArrayList<MapTile> mTilesLoaded; private static ArrayList<MapTile> mTilesLoaded;
// current center tile, values used to check if position has // TODO current boundary tiles, values used to check if position has
// changed for updating current tile list // changed for updating current tile list
private static long mTileX, mTileY;
private static float mPrevScale;
private static byte mPrevZoom;
private static boolean mInitial; private static boolean mInitial;
// private static MapPosition mCurPosition, mDrawPosition; // private static MapPosition mCurPosition, mDrawPosition;
private static int mWidth = 0, mHeight = 0; private static int mWidth = 0, mHeight = 0;
// maps zoom-level to available zoom-levels in MapDatabase
// e.g. 16->16, 15->16, 14->13, 13->13, 12->13,....
// private static int[] mZoomLevels;
private static float[] mTileCoords = new float[8];
private static int[] mBoundaryTiles = new int[8];
// used for passing tiles to be rendered from TileLoader(Main-Thread) to // used for passing tiles to be rendered from TileLoader(Main-Thread) to
// GLThread // GLThread
static final class TilesData { static final class TilesData {
@ -70,16 +78,61 @@ public class MapRenderer extends GLSurfaceView {
} }
} }
private static TilesData mCurrentTiles; /* package */static TilesData mCurrentTiles;
// maps zoom-level to available zoom-levels in MapDatabase private static ScanBox mScanBox = new ScanBox() {
// e.g. 16->16, 15->16, 14->13, 13->13, 12->13,....
private static int[] mZoomLevels; @Override
void setVisible(int y, int x1, int x2) {
MapTile[] tiles = mCurrentTiles.tiles;
int cnt = mCurrentTiles.cnt;
int max = mCurrentTiles.tiles.length;
int xmax = 1 << mZoom;
for (int x = x1; x < x2; x++) {
// MapTile holder = null;
MapTile tile = null;
// boolean found = false;
if (cnt == max) {
Log.d(TAG, "reached max currentTiles " + max);
break;
}
int xx = x;
if (x < 0 || x >= xmax) {
// flip-around date line
if (x < 0)
xx = xmax + x;
else
xx = x - xmax;
if (xx < 0 || xx >= xmax) {
// Log.d(TAG, "tile out of bounds " + y + " " + xx);
continue;
}
}
for (int i = 0; i < cnt; i++)
if (tiles[i].tileX == xx && tiles[i].tileY == y) {
tile = tiles[i];
break;
}
if (tile == null) {
tile = addTile(xx, y, mZoom, 0);
tiles[cnt++] = tile;
}
}
mCurrentTiles.cnt = cnt;
}
};
public MapRenderer(Context context, MapView mapView) { public MapRenderer(Context context, MapView mapView) {
super(context); super(context);
mMapView = mapView; mMapView = mapView;
mMapViewPosition = mapView.getMapViewPosition();
Log.d(TAG, "init GLSurfaceLayer"); Log.d(TAG, "init GLSurfaceLayer");
setEGLConfigChooser(new GlConfigChooser()); setEGLConfigChooser(new GlConfigChooser());
@ -116,16 +169,9 @@ public class MapRenderer extends GLSurfaceView {
if (mMapView == null) if (mMapView == null)
return; return;
MapPosition mapPosition = mMapView.getMapPosition().getMapPosition(); if (clear || mInitial) {
if (mapPosition == null) {
Log.d(TAG, "X no map position");
return;
}
if (clear) {
// make sure onDrawFrame is not running // make sure onDrawFrame is not running
GLRenderer.lock.lock(); GLRenderer.drawlock.lock();
// remove all tiles references // remove all tiles references
Log.d(TAG, "CLEAR"); Log.d(TAG, "CLEAR");
for (MapTile t : mTiles) for (MapTile t : mTiles)
@ -134,74 +180,71 @@ public class MapRenderer extends GLSurfaceView {
mTiles.clear(); mTiles.clear();
mTilesLoaded.clear(); mTilesLoaded.clear();
QuadTree.init(); QuadTree.init();
mInitial = true;
GLRenderer.lock.unlock();
}
if (mInitial) {
// set up TileData arrays that are passed to gl-thread // set up TileData arrays that are passed to gl-thread
int numTiles = (mWidth / (Tile.TILE_SIZE / 2) + 2) int num = mWidth;
* (mHeight / (Tile.TILE_SIZE / 2) + 2); if (mWidth < mHeight)
num = mHeight;
int size = Tile.TILE_SIZE >> 1;
int numTiles = (num * num) / (size * size) * 4;
mRenderer.clearTiles(numTiles); mRenderer.clearTiles(numTiles);
mCurrentTiles = new TilesData(numTiles); mCurrentTiles = new TilesData(numTiles);
MapInfo mapInfo = mMapView.getMapDatabase().getMapInfo(); // MapInfo mapInfo = mMapView.getMapDatabase().getMapInfo();
if (mapInfo != null) // if (mapInfo != null)
mZoomLevels = mapInfo.zoomLevel; // mZoomLevels = mapInfo.zoomLevel;
} GLRenderer.drawlock.unlock();
byte zoomLevel = mapPosition.zoomLevel;
float scale = mapPosition.scale;
long tileX = MercatorProjection.pixelXToTileX(mapPosition.x, zoomLevel)
* Tile.TILE_SIZE;
long tileY = MercatorProjection.pixelYToTileY(mapPosition.y, zoomLevel)
* Tile.TILE_SIZE;
int zdir = 0;
if (mInitial || mPrevZoom != zoomLevel) {
changedPos = true; changedPos = true;
} else if (tileX != mTileX || tileY != mTileY) {
if (mPrevScale - scale > 0 && scale > 1.2)
zdir = 1;
changedPos = true;
} else if (mPrevScale - scale > 0.2 || mPrevScale - scale < -0.2) {
if (mPrevScale - scale > 0 && scale > 1.2)
zdir = 1;
changedPos = true;
}
if (mInitial) {
mInitial = false; mInitial = false;
} }
mTileX = tileX; MapPosition mapPosition = mMapPosition;
mTileY = tileY; mMapViewPosition.getMapPosition(mapPosition, mTileCoords);
mPrevZoom = zoomLevel;
// GLRenderer.updatePosition(mapPosition); float s = Tile.TILE_SIZE;
// load some additional tiles more than currently visible
float scale = mapPosition.scale * 0.75f;
double px = mapPosition.x;
double py = mapPosition.y;
float[] coords = mTileCoords;
int zdir = 0;
if (!MapView.debugFrameTime) for (int i = 0; i < 8; i += 2) {
requestRender(); coords[i + 0] = (float) ((px + coords[i + 0] / scale) / s);
coords[i + 1] = (float) ((py + coords[i + 1] / scale) / s);
}
for (int i = 0; i < 8; i++)
if (mBoundaryTiles[i] != (int) coords[i]) {
changedPos = true;
break;
}
for (int i = 0; i < 8; i++)
mBoundaryTiles[i] = (int) coords[i];
// TODO all following should probably be done in an idler instead
// to drain queued events. need to check how android handles things.
if (changedPos) { if (changedPos) {
mPrevScale = scale;
updateVisibleList(mapPosition, zdir); updateVisibleList(mapPosition, zdir);
if (!MapView.debugFrameTime) if (!MapView.debugFrameTime)
requestRender(); requestRender();
int remove = mTiles.size() - GLRenderer.CACHE_TILES; int remove = mTiles.size() - GLRenderer.CACHE_TILES;
if (remove > 50) if (remove > CACHE_THRESHOLD)
limitCache(mapPosition, remove); limitCache(mapPosition, remove);
}
limitLoadQueue(); limitLoadQueue();
} else {
if (!MapView.debugFrameTime)
requestRender();
}
} }
/** /**
@ -214,102 +257,72 @@ public class MapRenderer extends GLSurfaceView {
* zoom direction * zoom direction
*/ */
private static void updateVisibleList(MapPosition mapPosition, int zdir) { private static void updateVisibleList(MapPosition mapPosition, int zdir) {
double x = mapPosition.x;
double y = mapPosition.y;
byte zoomLevel = mapPosition.zoomLevel;
float scale = mapPosition.scale;
double add = 1.0f / scale;
int offsetX = (int) ((mWidth >> 1) * add) + Tile.TILE_SIZE;
int offsetY = (int) ((mHeight >> 1) * add) + Tile.TILE_SIZE;
long pixelRight = (long) x + offsetX;
long pixelBottom = (long) y + offsetY;
long pixelLeft = (long) x - offsetX;
long pixelTop = (long) y - offsetY;
int tileLeft = MercatorProjection.pixelXToTileX(pixelLeft, zoomLevel);
int tileTop = MercatorProjection.pixelYToTileY(pixelTop, zoomLevel);
int tileRight = MercatorProjection.pixelXToTileX(pixelRight, zoomLevel);
int tileBottom = MercatorProjection.pixelYToTileY(pixelBottom, zoomLevel);
mJobList.clear(); mJobList.clear();
// set non processed tiles to isLoading == false // set non processed tiles to isLoading == false
mMapView.addJobs(null); mMapView.addJobs(null);
int tiles = 0;
int max = mCurrentTiles.tiles.length - 1;
boolean fetchChildren = false;
boolean fetchParent = false;
boolean fetchProxy = false;
if (mZoomLevels != null) {
// check MapDatabase zoom-level-mapping
if (mZoomLevels[zoomLevel] == 0) {
mCurrentTiles.cnt = 0; mCurrentTiles.cnt = 0;
mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles); mScanBox.scan(mTileCoords, mapPosition.zoomLevel);
return; // Log.d(TAG, "visible: " + mCurrentTiles.cnt + "/" +
} // mCurrentTiles.tiles.length);
GLRenderer.updateTiles(mCurrentTiles);
if (mZoomLevels[zoomLevel] > zoomLevel) { // note: this sets isLoading == true for all job tiles
fetchChildren = true; if (mJobList.size() > 0) {
fetchProxy = true; updateTileDistances(mJobList, mapPosition);
Collections.sort(mJobList);
} else if (mZoomLevels[zoomLevel] < zoomLevel) { mMapView.addJobs(mJobList);
fetchParent = true;
fetchProxy = true;
} }
} }
for (int yy = tileTop; yy <= tileBottom; yy++) { /* package */
for (int xx = tileLeft; xx <= tileRight; xx++) { static MapTile addTile(int x, int y, byte zoomLevel, int zdir) {
MapTile tile;
if (tiles == max) tile = QuadTree.getTile(x, y, zoomLevel);
break;
MapTile tile = QuadTree.getTile(xx, yy, zoomLevel);
if (tile == null) { if (tile == null) {
tile = new MapTile(xx, yy, zoomLevel); tile = new MapTile(x, y, zoomLevel);
QuadTree.add(tile); QuadTree.add(tile);
mTiles.add(tile); mTiles.add(tile);
} }
if (!fetchProxy && !tile.isActive()) { // if (!fetchProxy && !tile.isActive()) {
if (!tile.isActive()) {
mJobList.add(tile); mJobList.add(tile);
} }
mCurrentTiles.tiles[tiles++] = tile; // mCurrentTiles.tiles[tiles++] = tile;
if (fetchChildren) { // if (fetchChildren) {
byte z = (byte) (zoomLevel + 1); // byte z = (byte) (zoomLevel + 1);
for (int i = 0; i < 4; i++) { // for (int i = 0; i < 4; i++) {
int cx = (xx << 1) + (i % 2); // int cx = (xx << 1) + (i % 2);
int cy = (yy << 1) + (i >> 1); // int cy = (yy << 1) + (i >> 1);
//
// MapTile c = QuadTree.getTile(cx, cy, z);
//
// if (c == null) {
// c = new MapTile(cx, cy, z);
//
// QuadTree.add(c);
// mTiles.add(c);
// }
//
// if (!c.isActive()) {
// mJobList.add(c);
// }
// }
// }
MapTile c = QuadTree.getTile(cx, cy, z); // if (fetchParent || (!fetchProxy && zdir > 0 && zoomLevel > 0)) {
if (zdir > 0 && zoomLevel > 0) {
if (c == null) {
c = new MapTile(cx, cy, z);
QuadTree.add(c);
mTiles.add(c);
}
if (!c.isActive()) {
mJobList.add(c);
}
}
}
if (fetchParent || (!fetchProxy && zdir > 0 && zoomLevel > 0)) {
// prefetch parent // prefetch parent
MapTile p = tile.rel.parent.tile; MapTile p = tile.rel.parent.tile;
if (p == null) { if (p == null) {
p = new MapTile(xx >> 1, yy >> 1, (byte) (zoomLevel - 1)); p = new MapTile(x >> 1, y >> 1, (byte) (zoomLevel - 1));
QuadTree.add(p); QuadTree.add(p);
mTiles.add(p); mTiles.add(p);
@ -320,19 +333,7 @@ public class MapRenderer extends GLSurfaceView {
mJobList.add(p); mJobList.add(p);
} }
} }
} return tile;
}
// pass new tile list to glThread
mCurrentTiles.cnt = tiles;
mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
// note: this sets isLoading == true for all job tiles
if (mJobList.size() > 0) {
updateTileDistances(mJobList, mapPosition);
Collections.sort(mJobList);
mMapView.addJobs(mJobList);
}
} }
private static void clearTile(MapTile t) { private static void clearTile(MapTile t) {
@ -407,8 +408,6 @@ public class MapRenderer extends GLSurfaceView {
} }
private static void limitCache(MapPosition mapPosition, int remove) { private static void limitCache(MapPosition mapPosition, int remove) {
int removes = remove;
int size = mTiles.size(); int size = mTiles.size();
// remove orphaned tiles // remove orphaned tiles
@ -418,44 +417,46 @@ public class MapRenderer extends GLSurfaceView {
if (t.isLocked() || t.isActive()) { if (t.isLocked() || t.isActive()) {
i++; i++;
} else { } else {
// Log.d(TAG, "remove empty tile" + cur); // Log.d(TAG, "remove empty tile" + t);
clearTile(t); clearTile(t);
mTiles.remove(i); mTiles.remove(i);
removes--; remove--;
size--; size--;
} }
} }
// Log.d(TAG, "remove tiles: " + removes + " " + size); if (remove <= 0)
if (removes <= 0)
return; return;
updateTileDistances(mTiles, mapPosition); updateTileDistances(mTiles, mapPosition);
Collections.sort(mTiles); Collections.sort(mTiles);
for (int i = 1; i <= removes; i++) { for (int i = 1; i < remove; i++) {
MapTile t = mTiles.remove(size - i); MapTile t = mTiles.remove(size - i);
synchronized (t) { synchronized (t) {
if (t.isLocked()) { if (t.isLocked()) {
// dont remove tile used by renderthread // dont remove tile used by renderthread
Log.d(TAG, "X not removing " + t + " " + t.isLocked + " " Log.d(TAG, "X not removing " + t
+ t.distance); // + " " + t.isLocked
+ " " + t.distance);
mTiles.add(t); mTiles.add(t);
continue;
// } else if (t.isLoading) {
// // FIXME if we add tile back on next limit cache
// // this will be removed. clearTile could interfere with
// // MapGenerator... clear in passTile().
// Log.d(TAG, "X cancel loading " + t + " " + t.distance);
// t.isLoading = false;
// // mTiles.add(t);
} else {
clearTile(t);
} }
if (t.isLoading) {
// NOTE: if we add tile back then on next limitCache
// the tile will be removed. clearTile could interfere with
// MapGenerator. so clear in passTile() instead.
// mTiles.add(t);
t.isLoading = false;
Log.d(TAG, "X cancel loading " + t + " " + t.distance);
continue;
}
clearTile(t);
} }
} }
} }
@ -524,8 +525,8 @@ public class MapRenderer extends GLSurfaceView {
MapTile tile = (MapTile) jobTile; MapTile tile = (MapTile) jobTile;
if (!tile.isLoading) { if (!tile.isLoading) {
// no one should be able to use this tile now, mapgenerator passed // no one should be able to use this tile now, TileGenerator passed
// it, glthread does nothing until newdata is set. // it, GL-Thread does nothing until newdata is set.
Log.d(TAG, "passTile: canceled " + tile); Log.d(TAG, "passTile: canceled " + tile);
synchronized (mTilesLoaded) { synchronized (mTilesLoaded) {
mTilesLoaded.add(tile); mTilesLoaded.add(tile);
@ -573,4 +574,78 @@ public class MapRenderer extends GLSurfaceView {
super.onSizeChanged(w, h, oldw, oldh); super.onSizeChanged(w, h, oldw, oldh);
} }
// private static void updateVisibleList(MapPosition mapPosition, int zdir)
// {
// double x = mapPosition.x;
// double y = mapPosition.y;
// byte zoomLevel = mapPosition.zoomLevel;
// float scale = mapPosition.scale;
//
// double add = 1.0f / scale;
// int offsetX = (int) ((mWidth >> 1) * add) + Tile.TILE_SIZE;
// int offsetY = (int) ((mHeight >> 1) * add) + Tile.TILE_SIZE;
//
// long pixelRight = (long) x + offsetX;
// long pixelBottom = (long) y + offsetY;
// long pixelLeft = (long) x - offsetX;
// long pixelTop = (long) y - offsetY;
//
// int tileLeft = MercatorProjection.pixelXToTileX(pixelLeft, zoomLevel);
// int tileTop = MercatorProjection.pixelYToTileY(pixelTop, zoomLevel);
// int tileRight = MercatorProjection.pixelXToTileX(pixelRight, zoomLevel);
// int tileBottom = MercatorProjection.pixelYToTileY(pixelBottom,
// zoomLevel);
//
// mJobList.clear();
//
// // set non processed tiles to isLoading == false
// mMapView.addJobs(null);
//
// int tiles = 0;
// int max = mCurrentTiles.tiles.length - 1;
//
// // boolean fetchChildren = false;
// // boolean fetchParent = false;
// // boolean fetchProxy = false;
// // if (mZoomLevels != null) {
// // // check MapDatabase zoom-level-mapping
// // if (mZoomLevels[zoomLevel] == 0) {
// // mCurrentTiles.cnt = 0;
// // mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
// // return;
// // }
// //
// // if (mZoomLevels[zoomLevel] > zoomLevel) {
// // fetchChildren = true;
// // fetchProxy = true;
// //
// // } else if (mZoomLevels[zoomLevel] < zoomLevel) {
// // fetchParent = true;
// // fetchProxy = true;
// // }
// // }
//
// for (int yy = tileTop; yy <= tileBottom; yy++) {
// for (int xx = tileLeft; xx <= tileRight; xx++) {
//
// if (tiles == max)
// break;
//
// // MapTile tile =
// addTile(xx, yy, zoomLevel, zdir);
// // mCurrentTiles.tiles[tiles++] = tile;
// }
// }
//
// // pass new tile list to glThread
// mCurrentTiles.cnt = tiles;
// mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
//
// // note: this sets isLoading == true for all job tiles
// if (mJobList.size() > 0) {
// updateTileDistances(mJobList, mapPosition);
// Collections.sort(mJobList);
// mMapView.addJobs(mJobList);
// }
// }
} }

View File

@ -41,7 +41,7 @@ class MapTile extends JobTile {
/** /**
* tile is used by render thread. set by updateVisibleList (main thread). * tile is used by render thread. set by updateVisibleList (main thread).
*/ */
boolean isLocked; // boolean isLocked;
/** /**
* tile has new data to upload to gl * tile has new data to upload to gl
@ -63,29 +63,38 @@ class MapTile extends JobTile {
*/ */
QuadTree rel; QuadTree rel;
byte lastDraw = 0; int lastDraw = 0;
// keep track which tiles are locked as proxy for this tile // keep track which tiles are locked as proxy for this tile
final static int PROXY_PARENT = 16; final static int PROXY_PARENT = 16;
final static int PROXY_GRAMPA = 32; final static int PROXY_GRAMPA = 32;
final static int PROXY_HOLDER = 64;
// 1-8: children // 1-8: children
byte proxies; byte proxies;
// counting the tiles that use this tile as proxy // counting the tiles that use this tile as proxy
byte refs; byte refs;
byte locked;
// this tile sits in fo another tile. e.g. x:-1,y:0,z:1 for x:1,y:0
MapTile holder;
boolean isActive() { boolean isActive() {
return isLoading || newData || isReady; return isLoading || newData || isReady;
} }
boolean isLocked() { boolean isLocked() {
return isLocked || refs > 0; return locked > 0 || refs > 0;
} }
void lock() { void lock() {
isLocked = true; if (holder != null)
return;
if (isReady || newData) locked++;
if (locked > 1 || isReady || newData)
return; return;
MapTile p = rel.parent.tile; MapTile p = rel.parent.tile;
@ -113,9 +122,12 @@ class MapTile extends JobTile {
} }
void unlock() { void unlock() {
isLocked = false; if (holder != null)
return;
if (proxies == 0) locked--;
if (locked > 0 || proxies == 0)
return; return;
if ((proxies & (1 << 4)) != 0) { if ((proxies & (1 << 4)) != 0) {

View File

@ -41,15 +41,18 @@ import java.nio.FloatBuffer;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import org.oscim.utils.GlUtils; import org.oscim.utils.GlUtils;
import org.oscim.view.MapPosition;
import android.opengl.GLES20; import android.opengl.GLES20;
class PolygonRenderer { class PolygonRenderer {
private static final String TAG = "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 final int STENCIL_BITS = 8;
private static final float FADE_START = 1.3f;
private static PolygonLayer[] mFillPolys; private static PolygonLayer[] mFillPolys;
@ -76,7 +79,7 @@ class PolygonRenderer {
return true; return true;
} }
private static void fillPolygons(double zoom, float scale) { private static void fillPolygons(int zoom, float scale) {
boolean blend = false; boolean blend = false;
/* draw to framebuffer */ /* draw to framebuffer */
@ -96,7 +99,7 @@ class PolygonRenderer {
if (l.area.fade >= zoom || l.area.color[3] != 1.0) { if (l.area.fade >= zoom || l.area.color[3] != 1.0) {
/* fade in/out || draw alpha color */ /* fade in/out || draw alpha color */
if (l.area.fade >= zoom) { if (l.area.fade >= zoom) {
f = (scale > 1.3f ? scale : 1.3f) - f; f = (scale > FADE_START ? scale : FADE_START) - f;
if (f > 1.0f) if (f > 1.0f)
f = 1.0f; f = 1.0f;
} }
@ -159,8 +162,11 @@ class PolygonRenderer {
// stencil buffer index to start fill // stencil buffer index to start fill
private static int mStart; private static int mStart;
static PolygonLayer drawPolygons(final PolygonLayer layer, final int next, static PolygonLayer drawPolygons(MapPosition pos, PolygonLayer layer, int next,
final float[] matrix, final double zoom, final float scale, boolean first) { float[] matrix, boolean first) {
int zoom = pos.zoomLevel;
float scale = pos.scale;
glUseProgram(polygonProgram); glUseProgram(polygonProgram);
GLES20.glEnableVertexAttribArray(hPolygonVertexPosition); GLES20.glEnableVertexAttribArray(hPolygonVertexPosition);

View File

@ -17,23 +17,10 @@
package org.oscim.view.renderer; package org.oscim.view.renderer;
import org.oscim.view.renderer.MapRenderer.TilesData;
import android.util.FloatMath; import android.util.FloatMath;
import android.util.Log;
public class ScanBox { public abstract class ScanBox {
interface Callback {
void call(MapTile tile);
}
class SetVisible implements Callback {
@Override
public void call(MapTile tile) {
tile.isVisible = true;
}
}
static class Edge { static class Edge {
float x0, y0, x1, y1, dx, dy; float x0, y0, x1, y1, dx, dy;
@ -44,84 +31,50 @@ public class ScanBox {
this.y0 = y0; this.y0 = y0;
this.x1 = x1; this.x1 = x1;
this.y1 = y1; this.y1 = y1;
this.dx = x1 - x0; dx = x1 - x0;
this.dy = y1 - y0; dy = y1 - y0;
} else { } else {
this.x0 = x1; this.x0 = x1;
this.y0 = y1; this.y0 = y1;
this.x1 = x0; this.x1 = x0;
this.y1 = y0; this.y1 = y0;
this.dx = x0 - x1; dx = x0 - x1;
this.dy = y0 - y1; dy = y0 - y1;
} }
} }
} }
static Edge ab = new Edge(); private Edge ab = new Edge();
static Edge bc = new Edge(); private Edge bc = new Edge();
static Edge ca = new Edge(); private Edge ca = new Edge();
protected byte mZoom;
static void scanSpans(Edge e0, Edge e1) { void scan(float[] coords, byte zoom) {
mZoom = zoom;
// sort edge by x-coordinate ab.set(coords[0], coords[1], coords[2], coords[3]);
if (e0.x0 == e1.x0 && e0.y0 == e1.y0) { bc.set(coords[2], coords[3], coords[4], coords[5]);
if (e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1) { ca.set(coords[4], coords[5], coords[0], coords[1]);
Edge t = e0; scanTriangle();
e0 = e1;
e1 = t; ab.set(coords[4], coords[5], coords[6], coords[7]);
} bc.set(coords[6], coords[7], coords[0], coords[1]);
} else { ca.set(coords[0], coords[1], coords[4], coords[5]);
if (e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0) { scanTriangle();
Edge t = e0;
e0 = e1;
e1 = t;
}
} }
float m0 = e0.dx / e0.dy; /**
float m1 = e1.dx / e1.dy; * @param y
* ...
int d0 = e0.dx > 0 ? 1 : 0;// use y + 1 to compute x0 * @param x1
int d1 = e1.dx < 0 ? 1 : 0; // use y + 1 to compute x1 * ...
* @param x2
float x0, x1; * ...
*/
int y = (int) Math.max(0, FloatMath.floor(e1.y0)); void setVisible(int y, int x1, int x2) {
int bottom = (int) Math.min(mMax, FloatMath.ceil(e1.y1));
for (; y < bottom; y++) {
// float x0 = (m0 * Math.min(e0.dy, y + d0 - e0.y0) + e0.x0);
// float x1 = (m1 * Math.min(e1.dy, y + d1 - e1.y0) + e1.x0);
x0 = y + d0 - e0.y0;
if (e0.dy < x0)
x0 = e0.dy;
x0 = e0.x0 + m0 * x0;
if (x0 < 0)
x0 = 0;
else
x0 = FloatMath.ceil(x0);
x1 = y + d1 - e1.y0;
if (e1.dy < x1)
x1 = e1.dy;
x1 = e1.x0 + m1 * x1;
if (x1 < 0)
x1 = 0;
else
x1 = FloatMath.floor(x1);
setVisible(y, (int) x1, (int) x0);
// setVisible(y, (int) (x1 - 0.5f), (int) (x0 + 0.5f));
}
} }
static void scanTriangle() { private void scanTriangle() {
if (ab.dy > bc.dy) { if (ab.dy > bc.dy) {
Edge t = ab; Edge t = ab;
@ -138,6 +91,10 @@ public class ScanBox {
bc = ca; bc = ca;
ca = t; ca = t;
} }
// ca.dy > bc.dy > ab.dy
if (ca.dy == 0)
return;
if (ab.dy != 0) if (ab.dy != 0)
scanSpans(ca, ab); scanSpans(ca, ab);
@ -146,42 +103,68 @@ public class ScanBox {
scanSpans(ca, bc); scanSpans(ca, bc);
} }
private static int mMax; private static final int MAX_SLOPE = 4;
public static void scan(float[] coords, TilesData tiles, int max) { private void scanSpans(Edge e0, Edge e1) {
sTiles = tiles;
cntDoubles = 0;
mMax = max;
ab.set(coords[0], coords[1], coords[2], coords[3]); int y0 = (int) Math.max(0, FloatMath.floor(e1.y0));
bc.set(coords[2], coords[3], coords[4], coords[5]); int y1 = (int) Math.min((1 << mZoom), FloatMath.ceil(e1.y1));
ca.set(coords[4], coords[5], coords[0], coords[1]);
scanTriangle();
ab.set(coords[4], coords[5], coords[6], coords[7]); // sort edge by x-coordinate
bc.set(coords[6], coords[7], coords[0], coords[1]); if (e0.x0 == e1.x0 && e0.y0 == e1.y0) {
ca.set(coords[0], coords[1], coords[4], coords[5]); // bottom-flat
scanTriangle(); if (e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1) {
Edge t = e0;
// Log.d("..", "<doubles " + cntDoubles); e0 = e1;
e1 = t;
} }
} else {
private static TilesData sTiles; // top-flat
private static int cntDoubles; if (e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0) {
Edge t = e0;
private static void setVisible(int y, int x1, int x2) { e0 = e1;
e1 = t;
MapTile[] tiles = sTiles.tiles;
for (int i = 0, n = sTiles.cnt; i < n; i++) {
if (tiles[i].tileY == y) {
if (tiles[i].tileX >= x1 && tiles[i].tileX < x2) {
// if (tiles[i].isVisible) {
// Log.d("..", ">>>" + y + " " + tiles[i].tileX);
// cntDoubles++;
// }
tiles[i].isVisible = true;
} }
} }
float m0 = e0.dx / e0.dy;
float m1 = e1.dx / e1.dy;
// still needed?
if (m0 > MAX_SLOPE)
m0 = MAX_SLOPE;
else if (m0 < -MAX_SLOPE)
m0 = -MAX_SLOPE;
if (m1 > MAX_SLOPE)
m1 = MAX_SLOPE;
else if (m1 < -MAX_SLOPE)
m1 = -MAX_SLOPE;
int d0 = e0.dx > 0 ? 1 : 0; // use y + 1 to compute x0
int d1 = e1.dx < 0 ? 1 : 0; // use y + 1 to compute x1
float x0, x1, dy;
for (int y = y0; y < y1; y++) {
dy = y + d0 - e0.y0;
if (e0.dy < dy)
dy = e0.dy;
x0 = e0.x0 + m0 * dy;
x0 = FloatMath.ceil(x0);
dy = y + d1 - e1.y0;
if (e1.dy < dy)
dy = e1.dy;
x1 = e1.x0 + m1 * dy;
x1 = FloatMath.floor(x1);
if (x1 > x0)
Log.d("...", "X set visible" + y + " " + x1 + "/" + x0);
setVisible(y, (int) x1, (int) x0);
} }
} }
} }

View File

@ -19,7 +19,6 @@ class Shaders {
final static String lineVertexShader = "" final static String lineVertexShader = ""
+ "precision mediump float;" + "precision mediump float;"
// + "invariant gl_Position;"
+ "uniform mat4 u_mvp;" + "uniform mat4 u_mvp;"
+ "uniform float u_width;" + "uniform float u_width;"
+ "attribute vec2 a_position;" + "attribute vec2 a_position;"
@ -111,20 +110,20 @@ class Shaders {
+ "precision highp float; " + "precision highp float; "
+ "attribute vec4 vertex;" + "attribute vec4 vertex;"
+ "attribute vec2 tex_coord;" + "attribute vec2 tex_coord;"
+ "uniform mat4 mvp;" + "uniform mat4 u_mv;"
+ "uniform mat4 rotation;" + "uniform mat4 u_proj;"
+ "uniform float scale;" + "uniform float u_scale;"
+ "varying vec2 tex_c;" + "varying vec2 tex_c;"
+ "const vec2 div = vec2(1.0/4096.0,1.0/2048.0);" + "const vec2 div = vec2(1.0/4096.0,1.0/2048.0);"
+ "const float coord_scale = 0.125;" + "const float coord_scale = 0.125;"
+ "void main() {" + "void main() {"
+ " vec4 pos;" + " vec4 pos;"
+ " if (mod(vertex.x, 2.0) == 0.0){" + " if (mod(vertex.x, 2.0) == 0.0){"
+ " pos = rotation * (mvp * vec4(vertex.xy + vertex.zw * (1.0 / scale), 0.0, 1.0));" + " pos = u_proj * (u_mv * vec4(vertex.xy + vertex.zw * u_scale, 0.0, 1.0));"
+ " } else {" + " } else {"
// place as billboard // place as billboard
+ " vec4 dir = mvp * vec4(vertex.xy, 0.0, 1.0);" + " vec4 dir = u_mv * vec4(vertex.xy, 0.0, 1.0);"
+ " pos = rotation * (dir + vec4(vertex.zw * coord_scale, 0.0, 0.0));" + " pos = u_proj * (dir + vec4(vertex.zw * coord_scale, 0.0, 0.0));"
+ " }" + " }"
+ " gl_Position = pos;" + " gl_Position = pos;"
+ " tex_c = tex_coord * div;" + " tex_c = tex_coord * div;"
@ -175,7 +174,6 @@ class Shaders {
final static String textFragmentShader = "" final static String textFragmentShader = ""
+ "precision highp float;" + "precision highp float;"
+ "uniform sampler2D tex;" + "uniform sampler2D tex;"
+ "uniform vec4 col;"
+ "varying vec2 tex_c;" + "varying vec2 tex_c;"
+ "void main() {" + "void main() {"
+ " gl_FragColor = texture2D(tex, tex_c.xy);" + " gl_FragColor = texture2D(tex, tex_c.xy);"

View File

@ -54,8 +54,8 @@ public class TextRenderer {
private static int mVerticesVBO; private static int mVerticesVBO;
private static int mTextProgram; private static int mTextProgram;
private static int hTextUVPMatrix; private static int hTextMVMatrix;
private static int hTextRotationMatrix; private static int hTextProjectionMatrix;
private static int hTextVertex; private static int hTextVertex;
private static int hTextScale; private static int hTextScale;
private static int hTextTextureCoord; private static int hTextTextureCoord;
@ -83,11 +83,10 @@ public class TextRenderer {
mTextProgram = GlUtils.createProgram(Shaders.textVertexShader, mTextProgram = GlUtils.createProgram(Shaders.textVertexShader,
Shaders.textFragmentShader); Shaders.textFragmentShader);
hTextUVPMatrix = GLES20.glGetUniformLocation(mTextProgram, "mvp"); hTextMVMatrix = GLES20.glGetUniformLocation(mTextProgram, "u_mv");
hTextRotationMatrix = GLES20.glGetUniformLocation(mTextProgram, "rotation"); hTextProjectionMatrix = GLES20.glGetUniformLocation(mTextProgram, "u_proj");
hTextScale = GLES20.glGetUniformLocation(mTextProgram, "u_scale");
hTextVertex = GLES20.glGetAttribLocation(mTextProgram, "vertex"); hTextVertex = GLES20.glGetAttribLocation(mTextProgram, "vertex");
hTextScale = GLES20.glGetUniformLocation(mTextProgram, "scale");
hTextTextureCoord = GLES20.glGetAttribLocation(mTextProgram, "tex_coord"); hTextTextureCoord = GLES20.glGetAttribLocation(mTextProgram, "tex_coord");
} }
@ -150,12 +149,6 @@ public class TextRenderer {
indices[i + 3] = (short) (j + 2); indices[i + 3] = (short) (j + 2);
indices[i + 4] = (short) (j + 3); indices[i + 4] = (short) (j + 3);
indices[i + 5] = (short) (j + 0); indices[i + 5] = (short) (j + 0);
// indices[i + 0] = (short) (j + 0);
// indices[i + 1] = (short) (j + 0);
// indices[i + 2] = (short) (j + 1);
// indices[i + 3] = (short) (j + 3);
// indices[i + 4] = (short) (j + 2);
// indices[i + 5] = (short) (j + 2);
} }
mShortBuffer.clear(); mShortBuffer.clear();
@ -192,7 +185,7 @@ public class TextRenderer {
if (tex.tile == null) if (tex.tile == null)
break; break;
if (!tex.tile.isLocked) if (!tex.tile.isLocked())
break; break;
tex = null; tex = null;
@ -293,11 +286,10 @@ public class TextRenderer {
if (t.caption != null) { if (t.caption != null) {
x1 = x3 = (short) (SCALE * (-hw)); x1 = x3 = (short) (SCALE * (-hw));
y1 = y3 = (short) (SCALE * (-hh)); y1 = y3 = (short) (SCALE * (hh));
x2 = x4 = (short) (SCALE * (hw)); x2 = x4 = (short) (SCALE * (hw));
y2 = y4 = (short) (SCALE * (hh)); y2 = y4 = (short) (SCALE * (-hh));
} } else {
else {
float vx = t.x1 - t.x2; float vx = t.x1 - t.x2;
float vy = t.y1 - t.y2; float vy = t.y1 - t.y2;
float a = FloatMath.sqrt(vx * vx + vy * vy); float a = FloatMath.sqrt(vx * vx + vy * vy);
@ -322,14 +314,14 @@ public class TextRenderer {
// x3 = (short) (dx | 2); // x3 = (short) (dx | 2);
// y2 = (short) (dy | 2); // y2 = (short) (dy | 2);
x1 = (short) (SCALE * (vx * hw + ux * hh)); x1 = (short) (SCALE * (vx * hw - ux * hh));
y1 = (short) (SCALE * (vy * hw + uy * hh)); y1 = (short) (SCALE * (vy * hw - uy * hh));
x2 = (short) (SCALE * (-vx * hw + ux * hh)); x2 = (short) (SCALE * (-vx * hw - ux * hh));
y3 = (short) (SCALE * (-vy * hw + uy * hh)); y3 = (short) (SCALE * (-vy * hw - uy * hh));
x4 = (short) (SCALE * (-vx * hw - ux * hh)); x4 = (short) (SCALE * (-vx * hw + ux * hh));
y4 = (short) (SCALE * (-vy * hw - uy * hh)); y4 = (short) (SCALE * (-vy * hw + uy * hh));
x3 = (short) (SCALE * (vx * hw - ux * hh)); x3 = (short) (SCALE * (vx * hw + ux * hh));
y2 = (short) (SCALE * (vy * hw - uy * hh)); y2 = (short) (SCALE * (vy * hw + uy * hh));
} }
short u1 = (short) (SCALE * x); short u1 = (short) (SCALE * x);
@ -394,7 +386,8 @@ public class TextRenderer {
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap, GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap,
mBitmapFormat, mBitmapType); mBitmapFormat, mBitmapType);
// FIXME shouldnt be needed here, still looking for sometimes corrupted labels.. // FIXME shouldnt be needed here, still looking for sometimes corrupted
// labels..
GLES20.glFlush(); GLES20.glFlush();
return true; return true;
@ -412,7 +405,7 @@ public class TextRenderer {
for (int i = 0; i < mTextures.length; i++) { for (int i = 0; i < mTextures.length; i++) {
tex = mTextures[i]; tex = mTextures[i];
if (tex.tile == null || !tex.tile.isLocked) if (tex.tile == null) // || !tex.tile.isLocked)
continue; continue;
mShortBuffer.put(tex.vertices, 0, tex.length); mShortBuffer.put(tex.vertices, 0, tex.length);
@ -426,14 +419,14 @@ public class TextRenderer {
mShortBuffer); mShortBuffer);
} }
static void beginDraw(float scale, float[] rotation) { static void beginDraw(float scale, float[] projection) {
GLES20.glUseProgram(mTextProgram); GLES20.glUseProgram(mTextProgram);
GLES20.glEnableVertexAttribArray(hTextTextureCoord); GLES20.glEnableVertexAttribArray(hTextTextureCoord);
GLES20.glEnableVertexAttribArray(hTextVertex); GLES20.glEnableVertexAttribArray(hTextVertex);
GLES20.glUniform1f(hTextScale, scale); GLES20.glUniform1f(hTextScale, scale);
GLES20.glUniformMatrix4fv(hTextRotationMatrix, 1, false, rotation, 0); GLES20.glUniformMatrix4fv(hTextProjectionMatrix, 1, false, projection, 0);
if (debug) { if (debug) {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
@ -461,7 +454,7 @@ public class TextRenderer {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tile.texture.id); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tile.texture.id);
GLES20.glUniformMatrix4fv(hTextUVPMatrix, 1, false, matrix, 0); GLES20.glUniformMatrix4fv(hTextMVMatrix, 1, false, matrix, 0);
if (debug) { if (debug) {
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

View File

@ -136,8 +136,8 @@ final class WayDecorator {
} else if ((currentY - nextY) == 0) } else if ((currentY - nextY) == 0)
break; break;
float diff = ((diffX) / (diffY) - (float) (currentX - nextX) float diff = diffX / diffY -
/ (currentY - nextY)); (float) (currentX - nextX) / (currentY - nextY);
// skip segments with corners // skip segments with corners
if (diff >= 0.1f || diff <= -0.1f) if (diff >= 0.1f || diff <= -0.1f)
@ -221,8 +221,8 @@ final class WayDecorator {
// check overlapping labels of road with more than one // check overlapping labels of road with more than one
// way // way
short top2 = (t2.y1 < t2.y2 ? t2.y1 : t2.y2); short top2 = t2.y1 < t2.y2 ? t2.y1 : t2.y2;
short bot2 = (t2.y1 < t2.y2 ? t2.y2 : t2.y1); short bot2 = t2.y1 < t2.y2 ? t2.y2 : t2.y1;
if (x1 - 10 < t2.x2 && t2.x1 - 10 < x2 && top - 10 < bot2 if (x1 - 10 < t2.x2 && t2.x1 - 10 < x2 && top - 10 < bot2
&& top2 - 10 < bot) { && top2 - 10 < bot) {
@ -240,7 +240,8 @@ final class WayDecorator {
continue; continue;
} }
// Log.d("mapsforge", "add " + text + " " + first + " " + last); // Log.d("mapsforge", "add " + text + " " + first + " " +
// last);
if (previousX < currentX) { if (previousX < currentX) {
x1 = previousX; x1 = previousX;