diff --git a/src/org/oscim/database/IMapDatabase.java b/src/org/oscim/database/IMapDatabase.java index 8bea5626..f9889bf9 100644 --- a/src/org/oscim/database/IMapDatabase.java +++ b/src/org/oscim/database/IMapDatabase.java @@ -15,7 +15,7 @@ */ package org.oscim.database; -import org.oscim.generator.JobTile; +import org.oscim.layers.tile.JobTile; /** * diff --git a/src/org/oscim/database/mapfile/MapDatabase.java b/src/org/oscim/database/mapfile/MapDatabase.java index 793b6709..f82fddc9 100644 --- a/src/org/oscim/database/mapfile/MapDatabase.java +++ b/src/org/oscim/database/mapfile/MapDatabase.java @@ -27,7 +27,7 @@ import org.oscim.database.MapOptions; import org.oscim.database.mapfile.header.MapFileHeader; import org.oscim.database.mapfile.header.MapFileInfo; import org.oscim.database.mapfile.header.SubFileParameter; -import org.oscim.generator.JobTile; +import org.oscim.layers.tile.JobTile; import android.util.Log; diff --git a/src/org/oscim/database/oscimap/MapDatabase.java b/src/org/oscim/database/oscimap/MapDatabase.java index 3aefb0d5..a7951c33 100644 --- a/src/org/oscim/database/oscimap/MapDatabase.java +++ b/src/org/oscim/database/oscimap/MapDatabase.java @@ -30,7 +30,7 @@ import org.oscim.database.IMapDatabase; import org.oscim.database.IMapDatabaseCallback; import org.oscim.database.MapInfo; import org.oscim.database.MapOptions; -import org.oscim.generator.JobTile; +import org.oscim.layers.tile.JobTile; import android.os.Environment; import android.os.SystemClock; diff --git a/src/org/oscim/database/pbmap/MapDatabase.java b/src/org/oscim/database/pbmap/MapDatabase.java index 737afb5a..00cb61d5 100644 --- a/src/org/oscim/database/pbmap/MapDatabase.java +++ b/src/org/oscim/database/pbmap/MapDatabase.java @@ -43,7 +43,7 @@ import org.oscim.database.IMapDatabase; import org.oscim.database.IMapDatabaseCallback; import org.oscim.database.MapInfo; import org.oscim.database.MapOptions; -import org.oscim.generator.JobTile; +import org.oscim.layers.tile.JobTile; import android.os.Environment; import android.os.SystemClock; diff --git a/src/org/oscim/database/test/MapDatabase.java b/src/org/oscim/database/test/MapDatabase.java index 8a682ff8..61e6def7 100644 --- a/src/org/oscim/database/test/MapDatabase.java +++ b/src/org/oscim/database/test/MapDatabase.java @@ -26,7 +26,7 @@ import org.oscim.database.IMapDatabase; import org.oscim.database.IMapDatabaseCallback; import org.oscim.database.MapInfo; import org.oscim.database.MapOptions; -import org.oscim.generator.JobTile; +import org.oscim.layers.tile.JobTile; /** * diff --git a/src/org/oscim/layers/InputLayer.java b/src/org/oscim/layers/InputLayer.java new file mode 100644 index 00000000..6e14f615 --- /dev/null +++ b/src/org/oscim/layers/InputLayer.java @@ -0,0 +1,228 @@ +/* + * Copyright 2012 osmdroid authors + * Copyright 2013 Hannes Janetzek + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . + */ +package org.oscim.layers; + +import org.oscim.view.MapView; + +import android.view.KeyEvent; +import android.view.MotionEvent; + +public abstract class InputLayer extends Layer { + + public InputLayer(MapView mapView) { + super(mapView); + + } + /** + * By default does nothing (return false). If you handled the + * Event, return true, otherwise return false. If + * you returned true none of the following Overlays or the + * underlying {@link MapView} has the chance to handle this event. + * + * @param keyCode + * ... + * @param event + * ... + * @return ... + */ + public boolean onKeyDown(int keyCode, KeyEvent event) { + return false; + } + + /** + * By default does nothing (return false). If you handled the + * Event, return true, otherwise return false. If + * you returned true none of the following Overlays or the + * underlying {@link MapView} has the chance to handle this event. + * + * @param keyCode + * ... + * @param event + * ... + * @return ... + */ + public boolean onKeyUp(int keyCode, KeyEvent event) { + return false; + } + + /** + * You can prevent all(!) other Touch-related events from happening!
+ * By default does nothing (return false). If you handled the + * Event, return true, otherwise return false. If + * you returned true none of the following Overlays or the + * underlying {@link MapView} has the chance to handle this event. + * + * @param e + * ... + * @return ... + */ + public boolean onTouchEvent(MotionEvent e) { + return false; + } + + /** + * By default does nothing (return false). If you handled the + * Event, return true, otherwise return false. If + * you returned true none of the following Overlays or the + * underlying {@link MapView} has the chance to handle this event. + * + * @param e + * ... + * @return ... + */ + public boolean onTrackballEvent(MotionEvent e) { + return false; + } + + /** GestureDetector.OnDoubleTapListener **/ + + /** + * By default does nothing (return false). If you handled the + * Event, return true, otherwise return false. If + * you returned true none of the following Overlays or the + * underlying {@link MapView} has the chance to handle this event. + * + * @param e + * ... + * @return ... + */ + public boolean onDoubleTap(MotionEvent e) { + return false; + } + + /** + * By default does nothing (return false). If you handled the + * Event, return true, otherwise return false. If + * you returned true none of the following Overlays or the + * underlying {@link MapView} has the chance to handle this event. + * + * @param e + * ... + * @return ... + */ + public boolean onDoubleTapEvent(MotionEvent e) { + return false; + } + + /** + * By default does nothing (return false). If you handled the + * Event, return true, otherwise return false. If + * you returned true none of the following Overlays or the + * underlying {@link MapView} has the chance to handle this event. + * + * @param e + * ... + * @return ... + */ + public boolean onSingleTapConfirmed(MotionEvent e) { + return false; + } + + /** OnGestureListener **/ + + /** + * By default does nothing (return false). If you handled the + * Event, return true, otherwise return false. If + * you returned true none of the following Overlays or the + * underlying {@link MapView} has the chance to handle this event. + * + * @param e + * ... + * @return ... + */ + public boolean onDown(MotionEvent e) { + return false; + } + + /** + * By default does nothing (return false). If you handled the + * Event, return true, otherwise return false. If + * you returned true none of the following Overlays or the + * underlying {@link MapView} has the chance to handle this event. + * + * @param pEvent1 + * ... + * @param pEvent2 + * ... + * @param pVelocityX + * ... + * @param pVelocityY + * ... + * @return ... + */ + public boolean onFling(MotionEvent pEvent1, MotionEvent pEvent2, + float pVelocityX, float pVelocityY) { + return false; + } + + /** + * By default does nothing (return false). If you handled the + * Event, return true, otherwise return false. If + * you returned true none of the following Overlays or the + * underlying {@link MapView} has the chance to handle this event. + * + * @param e + * ... + * @return ... + */ + public boolean onLongPress(MotionEvent e) { + return false; + } + + /** + * By default does nothing (return false). If you handled the + * Event, return true, otherwise return false. If + * you returned true none of the following Overlays or the + * underlying {@link MapView} has the chance to handle this event. + * + * @param pEvent1 + * ... + * @param pEvent2 + * ... + * @param pDistanceX + * ... + * @param pDistanceY + * ... + * @return ... + */ + public boolean onScroll(MotionEvent pEvent1, MotionEvent pEvent2, + float pDistanceX, float pDistanceY) { + return false; + } + + /** + * @param pEvent + * ... + */ + public void onShowPress(MotionEvent pEvent) { + return; + } + + /** + * By default does nothing (return false). If you handled the + * Event, return true, otherwise return false. If + * you returned true none of the following Overlays or the + * underlying {@link MapView} has the chance to handle this event. + * + * @param e + * ... + * @return ... + */ + public boolean onSingleTapUp(MotionEvent e) { + return false; + } + +} diff --git a/src/org/oscim/layers/Layer.java b/src/org/oscim/layers/Layer.java new file mode 100644 index 00000000..6584fbdb --- /dev/null +++ b/src/org/oscim/layers/Layer.java @@ -0,0 +1,74 @@ +/* + * Copyright 2013 Hannes Janetzek + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . + */ +package org.oscim.layers; + +import org.oscim.core.MapPosition; +import org.oscim.renderer.overlays.RenderOverlay; +import org.oscim.view.MapView; + +public class Layer { + public Layer(MapView mapView) { + mMapView = mapView; + } + + private boolean mEnabled = true; + protected final MapView mMapView; + + /** RenderOverlay used to draw this layer. To be implemented by sub-classes */ + protected RenderOverlay mLayer; + + public RenderOverlay getLayer() { + return mLayer; + } + + /** + */ + public void setEnabled(boolean pEnabled) { + mEnabled = pEnabled; + } + + /** + */ + public boolean isEnabled() { + return mEnabled; + } + + + /** + * Called before each frame render request (on main thread). + * + * @param mapPosition + * current MapPosition + * @param changed + * true when MapPosition has changed since last call + */ + public void onUpdate(MapPosition mapPosition, boolean changed) { + + } + + + /** + * Override to perform clean up of resources before shutdown. By default + * does nothing. + */ + public void onDetach() { + // FIXME call to this function is not implemented + } + + public void destroy() { + // TODO Auto-generated method stub + + } +} diff --git a/src/org/oscim/generator/JobQueue.java b/src/org/oscim/layers/tile/JobQueue.java similarity index 93% rename from src/org/oscim/generator/JobQueue.java rename to src/org/oscim/layers/tile/JobQueue.java index 6805b832..30814a4b 100644 --- a/src/org/oscim/generator/JobQueue.java +++ b/src/org/oscim/layers/tile/JobQueue.java @@ -13,10 +13,10 @@ * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see . */ -package org.oscim.generator; +package org.oscim.layers.tile; -import static org.oscim.generator.JobTile.STATE_LOADING; -import static org.oscim.generator.JobTile.STATE_NONE; +import static org.oscim.layers.tile.JobTile.STATE_LOADING; +import static org.oscim.layers.tile.JobTile.STATE_NONE; /** * A JobQueue keeps the list of pending jobs for a MapView and prioritizes them. diff --git a/src/org/oscim/generator/JobTile.java b/src/org/oscim/layers/tile/JobTile.java similarity index 98% rename from src/org/oscim/generator/JobTile.java rename to src/org/oscim/layers/tile/JobTile.java index f4bc4ca9..984d4b3f 100644 --- a/src/org/oscim/generator/JobTile.java +++ b/src/org/oscim/layers/tile/JobTile.java @@ -12,7 +12,7 @@ * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see . */ -package org.oscim.generator; +package org.oscim.layers.tile; import org.oscim.core.Tile; diff --git a/src/org/oscim/renderer/MapTile.java b/src/org/oscim/layers/tile/MapTile.java similarity index 88% rename from src/org/oscim/renderer/MapTile.java rename to src/org/oscim/layers/tile/MapTile.java index 429efe59..74a290a4 100644 --- a/src/org/oscim/renderer/MapTile.java +++ b/src/org/oscim/layers/tile/MapTile.java @@ -12,11 +12,11 @@ * You should have received a copy of the GNU Lesser General License along with * this program. If not, see . */ -package org.oscim.renderer; +package org.oscim.layers.tile; -import org.oscim.generator.JobTile; import org.oscim.renderer.layer.Layers; import org.oscim.renderer.layer.TextItem; +import org.oscim.utils.quadtree.QuadTree; /** * Extends Tile class for concurrent use in TileManager, @@ -41,7 +41,7 @@ public final class MapTile extends JobTile { /** * Pointer to access relatives in QuadTree */ - public QuadTree rel; + public QuadTree rel; int lastDraw = 0; @@ -92,26 +92,24 @@ public final class MapTile extends JobTile { return; // lock all tiles that could serve as proxy - MapTile p = rel.parent.tile; + MapTile p = rel.parent.item; if (p != null && (p.state != 0)) { proxies |= PROXY_PARENT; p.refs++; } - p = rel.parent.parent.tile; + p = rel.parent.parent.item; if (p != null && (p.state != 0)) { proxies |= PROXY_GRAMPA; p.refs++; } for (int j = 0; j < 4; j++) { - if (rel.child[j] != null) { - p = rel.child[j].tile; - if (p != null && (p.state != 0)) { - proxies |= (1 << j); - p.refs++; - } - } + if ((p = rel.get(j)) == null || p.state == 0) + continue; + + proxies |= (1 << j); + p.refs++; } } @@ -120,14 +118,14 @@ public final class MapTile extends JobTile { return; if ((proxies & PROXY_PARENT) != 0) - rel.parent.tile.refs--; + rel.parent.item.refs--; if ((proxies & PROXY_GRAMPA) != 0) - rel.parent.parent.tile.refs--; + rel.parent.parent.item.refs--; for (int i = 0; i < 4; i++) { if ((proxies & (1 << i)) != 0) - rel.child[i].tile.refs--; + rel.get(i).refs--; } proxies = 0; } diff --git a/src/org/oscim/generator/MapWorker.java b/src/org/oscim/layers/tile/MapWorker.java similarity index 96% rename from src/org/oscim/generator/MapWorker.java rename to src/org/oscim/layers/tile/MapWorker.java index c11eb04c..9627d094 100644 --- a/src/org/oscim/generator/MapWorker.java +++ b/src/org/oscim/layers/tile/MapWorker.java @@ -1,6 +1,6 @@ /* * Copyright 2010, 2011, 2012 mapsforge.org - * + * Copyright 2013 Hannes 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. @@ -12,9 +12,8 @@ * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see . */ -package org.oscim.generator; +package org.oscim.layers.tile; -import org.oscim.renderer.TileManager; import org.oscim.utils.PausableThread; /** @@ -39,6 +38,7 @@ public class MapWorker extends PausableThread { */ public MapWorker(int id, JobQueue jobQueue, TileGenerator tileGenerator, TileManager tileManager) { + super(); mJobQueue = jobQueue; mMapGenerator = tileGenerator; diff --git a/src/org/oscim/generator/TileDistanceSort.java b/src/org/oscim/layers/tile/TileDistanceSort.java similarity index 98% rename from src/org/oscim/generator/TileDistanceSort.java rename to src/org/oscim/layers/tile/TileDistanceSort.java index cd6a6d84..dc1af2de 100644 --- a/src/org/oscim/generator/TileDistanceSort.java +++ b/src/org/oscim/layers/tile/TileDistanceSort.java @@ -12,7 +12,7 @@ * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see . */ -package org.oscim.generator; +package org.oscim.layers.tile; /** * Sort Tiles by 'distance' value. diff --git a/src/org/oscim/generator/TileGenerator.java b/src/org/oscim/layers/tile/TileGenerator.java similarity index 94% rename from src/org/oscim/generator/TileGenerator.java rename to src/org/oscim/layers/tile/TileGenerator.java index 3b23c4a9..b951c27d 100644 --- a/src/org/oscim/generator/TileGenerator.java +++ b/src/org/oscim/layers/tile/TileGenerator.java @@ -12,11 +12,12 @@ * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see . */ -package org.oscim.generator; +package org.oscim.layers.tile; + import static org.oscim.core.MapElement.GEOM_LINE; import static org.oscim.core.MapElement.GEOM_POINT; import static org.oscim.core.MapElement.GEOM_POLY; -import static org.oscim.generator.JobTile.STATE_NONE; +import static org.oscim.layers.tile.JobTile.STATE_NONE; import java.util.Arrays; @@ -25,9 +26,8 @@ import org.oscim.core.MercatorProjection; import org.oscim.core.Tag; import org.oscim.core.Tile; import org.oscim.database.IMapDatabase; +import org.oscim.database.IMapDatabase.QueryResult; import org.oscim.database.IMapDatabaseCallback; -import org.oscim.database.QueryResult; -import org.oscim.renderer.MapTile; import org.oscim.renderer.layer.ExtrusionLayer; import org.oscim.renderer.layer.Layers; import org.oscim.renderer.layer.LineLayer; @@ -71,12 +71,18 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback { private static final Tag[] debugTagWay = { new Tag("debug", "way") }; private static final Tag[] debugTagArea = { new Tag("debug", "area") }; + // replacement for variable value tags that should not be matched by RenderTheme + // FIXME make this general, maybe subclass tags + private static final Tag mTagEmptyName = new Tag(Tag.TAG_KEY_NAME, null, false); + private static final Tag mTagEmptyHouseNr = new Tag(Tag.TAG_KEY_HOUSE_NUMBER, null, false); + private final MapElement mDebugWay, mDebugPoint; - private static RenderTheme renderTheme; - private static int renderLevels; private static DebugSettings debug; + private RenderTheme renderTheme; + private int renderLevels; + // current MapDatabase used by this TileGenerator private IMapDatabase mMapDatabase; @@ -95,16 +101,12 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback { private float mLatScaleFactor; private float mGroundResolution; - // replacement for variable value tags that should not be matched by RenderTheme - // FIXME make this general, maybe subclass tags - private final static Tag mTagEmptyName = new Tag(Tag.TAG_KEY_NAME, null, false); - private final static Tag mTagEmptyHouseNr = new Tag(Tag.TAG_KEY_HOUSE_NUMBER, null, false); private Tag mTagName; private Tag mTagHouseNr; private final LineClipper mClipper; - public static void setRenderTheme(RenderTheme theme) { + public void setRenderTheme(RenderTheme theme) { renderTheme = theme; renderLevels = theme.getLevels(); } @@ -118,21 +120,21 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback { public TileGenerator() { mClipper = new LineClipper(0, 0, Tile.SIZE, Tile.SIZE, true); - MapElement m = mDebugWay = new MapElement(); - m.startLine(); - int s = Tile.SIZE; - m.addPoint(0, 0); - m.addPoint(0, s); - m.addPoint(s, s); - m.addPoint(s, 0); - m.addPoint(0, 0); - m.tags = new Tag[] { new Tag("debug", "box") }; - m.geometryType = GEOM_LINE; + MapElement m = mDebugWay = new MapElement(); + m.startLine(); + int s = Tile.SIZE; + m.addPoint(0, 0); + m.addPoint(0, s); + m.addPoint(s, s); + m.addPoint(s, 0); + m.addPoint(0, 0); + m.tags = new Tag[] { new Tag("debug", "box") }; + m.geometryType = GEOM_LINE; - m = mDebugPoint= new MapElement(); - m.startPoints(); - m.addPoint(s >> 1, 10); - m.geometryType = GEOM_POINT; + m = mDebugPoint = new MapElement(); + m.startPoints(); + m.addPoint(s >> 1, 10); + m.geometryType = GEOM_POINT; } public void cleanup() { @@ -309,7 +311,6 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback { mElement = null; } - private void debugUnmatched(boolean closed, Tag[] tags) { Log.d(TAG, "DBG way not matched: " + closed + " " + Arrays.deepToString(tags)); diff --git a/src/org/oscim/layers/tile/TileLayer.java b/src/org/oscim/layers/tile/TileLayer.java new file mode 100644 index 00000000..87b31ee9 --- /dev/null +++ b/src/org/oscim/layers/tile/TileLayer.java @@ -0,0 +1,332 @@ +/* + * Copyright 2013 Hannes Janetzek + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . + */ +package org.oscim.layers.tile; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import javax.xml.parsers.ParserConfigurationException; + +import org.oscim.core.GeoPoint; +import org.oscim.core.MapPosition; +import org.oscim.database.IMapDatabase; +import org.oscim.database.IMapDatabase.OpenResult; +import org.oscim.database.MapDatabaseFactory; +import org.oscim.database.MapDatabases; +import org.oscim.database.MapInfo; +import org.oscim.database.MapOptions; +import org.oscim.layers.Layer; +import org.oscim.renderer.GLRenderer; +import org.oscim.theme.ExternalRenderTheme; +import org.oscim.theme.InternalRenderTheme; +import org.oscim.theme.RenderTheme; +import org.oscim.theme.RenderThemeHandler; +import org.oscim.theme.Theme; +import org.oscim.view.MapView; +import org.xml.sax.SAXException; + +import android.util.Log; + +public class TileLayer extends Layer { + private final static String TAG = TileLayer.class.getName(); + + private boolean mClearMap = true; + + private final TileManager mTileManager; + + private final JobQueue mJobQueue; + // TODO use 1 download and 1 generator thread instead + private final MapWorker mMapWorkers[]; + private final int mNumMapWorkers = 4; + private final TileGenerator mTileGenerators[]; + + public TileLayer(MapView mapView) { + super(mapView); + mTileManager = new TileManager(mapView, this); + mJobQueue = new JobQueue(); + mMapWorkers = new MapWorker[mNumMapWorkers]; + mTileGenerators = new TileGenerator[mNumMapWorkers]; + + TileGenerator.setDebugSettings(mapView.getDebugSettings()); + + for (int i = 0; i < mNumMapWorkers; i++) { + mTileGenerators[i] = new TileGenerator(); + mMapWorkers[i] = new MapWorker(i, mJobQueue, mTileGenerators[i], mTileManager); + mMapWorkers[i].start(); + } + + mLayer = new TileRenderLayer(mapView, mTileManager); + } + + public TileRenderLayer getTileLayer(){ + return (TileRenderLayer)mLayer; + } + + + @Override + public void onUpdate(MapPosition mapPosition, boolean changed) { + + if (mClearMap){ + mTileManager.init(mMapView.getWidth(), mMapView.getHeight()); + mClearMap = false; + changed = true; + Log.d(TAG, "init TileManager ----- "); + } + if (changed) + mTileManager.update(mapPosition); + } + + + @Override + public void destroy(){ + mTileManager.destroy(); + + for (MapWorker mapWorker : mMapWorkers) { + mapWorker.pause(); + mapWorker.interrupt(); + + mapWorker.getTileGenerator().getMapDatabase().close(); + + try { + mapWorker.join(10000); + } catch (InterruptedException e) { + // restore the interrupted status + Thread.currentThread().interrupt(); + } + } + } + + private void clearMap() { + // clear tile and overlay data before next draw + mClearMap = true; + } + + private MapOptions mMapOptions; + private IMapDatabase mMapDatabase; + private String mRenderTheme; + + /** + * Sets the MapDatabase for this MapView. + * + * @param options + * the new MapDatabase options. + * @return true if MapDatabase changed + */ + public boolean setMapDatabase(MapOptions options) { + Log.i(TAG, "setMapDatabase: " + options.db.name()); + + if (mMapOptions != null && mMapOptions.equals(options)) + return true; + + mapWorkersPause(true); + + mJobQueue.clear(); + mMapOptions = options; + + mMapDatabase = null; + + for (int i = 0; i < mNumMapWorkers; i++) { + MapWorker mapWorker = mMapWorkers[i]; + + IMapDatabase mapDatabase = MapDatabaseFactory + .createMapDatabase(options.db); + + OpenResult result = mapDatabase.open(options); + + if (result != OpenResult.SUCCESS) { + Log.d(TAG, "failed open db: " + result.getErrorMessage()); + } + + TileGenerator tileGenerator = mapWorker.getTileGenerator(); + tileGenerator.setMapDatabase(mapDatabase); + + // TODO this could be done in a cleaner way.. + if (mMapDatabase == null) + mMapDatabase = mapDatabase; + } + + if (options.db == MapDatabases.OSCIMAP_READER || + options.db == MapDatabases.MAP_READER || + options.db == MapDatabases.TEST_READER) + MapView.enableClosePolygons = true; + else + MapView.enableClosePolygons = false; + + clearMap(); + + mapWorkersProceed(); + + return true; + } + + public Map getMapOptions() { + return mMapOptions; + } + + public MapPosition getMapFileCenter() { + if (mMapDatabase == null) + return null; + + MapInfo mapInfo = mMapDatabase.getMapInfo(); + if (mapInfo == null) + return null; + + GeoPoint startPos = mapInfo.startPosition; + + if (startPos == null) + startPos = mapInfo.mapCenter; + + if (startPos == null) + startPos = new GeoPoint(0, 0); + + MapPosition mapPosition = new MapPosition(); + mapPosition.setPosition(startPos); + + if (mapInfo.startZoomLevel == null) + mapPosition.setZoomLevel(12); + else + mapPosition.setZoomLevel((mapInfo.startZoomLevel).byteValue()); + + return mapPosition; + } + public String getRenderTheme() { + return mRenderTheme; + } + /** + * Sets the internal theme which is used for rendering the map. + * + * @param internalRenderTheme + * the internal rendering theme. + * @return ... + * @throws IllegalArgumentException + * if the supplied internalRenderTheme is null. + */ + public boolean setRenderTheme(InternalRenderTheme internalRenderTheme) { + if (internalRenderTheme == null) { + throw new IllegalArgumentException("render theme must not be null"); + } + + if (internalRenderTheme.name() == mRenderTheme) + return true; + + boolean ret = setRenderTheme((Theme) internalRenderTheme); + if (ret) { + mRenderTheme = internalRenderTheme.name(); + } + + clearMap(); + + return ret; + } + /** + * Sets the theme file which is used for rendering the map. + * + * @param renderThemePath + * the path to the XML file which defines the rendering theme. + * @throws IllegalArgumentException + * if the supplied internalRenderTheme is null. + * @throws FileNotFoundException + * if the supplied file does not exist, is a directory or cannot + * be read. + */ + public void setRenderTheme(String renderThemePath) throws FileNotFoundException { + if (renderThemePath == null) { + throw new IllegalArgumentException("render theme path must not be null"); + } + + boolean ret = setRenderTheme(new ExternalRenderTheme(renderThemePath)); + if (ret) { + mRenderTheme = renderThemePath; + } + + clearMap(); + } + + private boolean setRenderTheme(Theme theme) { + + mapWorkersPause(true); + + InputStream inputStream = null; + try { + inputStream = theme.getRenderThemeAsStream(); + RenderTheme t = RenderThemeHandler.getRenderTheme(inputStream); + t.scaleTextSize(1 + (MapView.dpi / 240 - 1) * 0.5f); + + // FIXME !!! + GLRenderer.setRenderTheme(t); + + for (TileGenerator g : mTileGenerators) + g.setRenderTheme(t); + + return true; + } catch (ParserConfigurationException e) { + Log.e(TAG, e.getMessage()); + } catch (SAXException e) { + Log.e(TAG, e.getMessage()); + } catch (IOException e) { + Log.e(TAG, e.getMessage()); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (IOException e) { + Log.e(TAG, e.getMessage()); + } + mapWorkersProceed(); + } + return false; + } + /** + * add jobs and remember MapWorkers that stuff needs to be done + * + * @param jobs + * tile jobs + */ + public void addJobs(JobTile[] jobs) { + if (jobs == null) { + mJobQueue.clear(); + return; + } + mJobQueue.setJobs(jobs); + + for (int i = 0; i < mNumMapWorkers; i++) { + MapWorker m = mMapWorkers[i]; + synchronized (m) { + m.notify(); + } + } + } + + private void mapWorkersPause(boolean wait) { + for (MapWorker mapWorker : mMapWorkers) { + if (!mapWorker.isPausing()) + mapWorker.pause(); + } + if (wait) { + for (MapWorker mapWorker : mMapWorkers) { + if (!mapWorker.isPausing()) + mapWorker.awaitPausing(); + } + } + } + + private void mapWorkersProceed() { + for (MapWorker mapWorker : mMapWorkers) + mapWorker.proceed(); + } +} diff --git a/src/org/oscim/renderer/TileManager.java b/src/org/oscim/layers/tile/TileManager.java similarity index 87% rename from src/org/oscim/renderer/TileManager.java rename to src/org/oscim/layers/tile/TileManager.java index c13f2ccd..1ce273b9 100644 --- a/src/org/oscim/renderer/TileManager.java +++ b/src/org/oscim/layers/tile/TileManager.java @@ -13,21 +13,24 @@ * this program. If not, see . */ -package org.oscim.renderer; +package org.oscim.layers.tile; -import static org.oscim.generator.JobTile.STATE_LOADING; -import static org.oscim.generator.JobTile.STATE_NEW_DATA; -import static org.oscim.generator.JobTile.STATE_NONE; +import static org.oscim.layers.tile.JobTile.STATE_LOADING; +import static org.oscim.layers.tile.JobTile.STATE_NEW_DATA; +import static org.oscim.layers.tile.JobTile.STATE_NONE; import java.util.ArrayList; import java.util.Arrays; import org.oscim.core.MapPosition; import org.oscim.core.Tile; -import org.oscim.generator.JobTile; -import org.oscim.generator.TileDistanceSort; +import org.oscim.renderer.BufferObject; +import org.oscim.renderer.GLRenderer; +import org.oscim.renderer.ScanBox; import org.oscim.renderer.layer.TextItem; import org.oscim.utils.FastMath; +import org.oscim.utils.quadtree.QuadTree; +import org.oscim.utils.quadtree.QuadTreeIndex; import org.oscim.view.MapView; import org.oscim.view.MapViewPosition; @@ -40,6 +43,8 @@ import android.util.Log; * - make it general for reuse in tile-overlays */ public class TileManager { + private static final int CACHE_TILES_MAX = 250; + static final String TAG = TileManager.class.getSimpleName(); private final static int MAX_ZOOMLEVEL = 17; private final static int MIN_ZOOMLEVEL = 2; @@ -71,21 +76,53 @@ public class TileManager { private final ArrayList mJobs; // counter to check whether current TileSet has changed - private static int mUpdateSerial; + private int mUpdateSerial; // lock for TileSets while updating MapTile locks private final Object mTilelock = new Object(); + // need to keep track of TileSets to clear on reset... + private final ArrayList mTileSets = new ArrayList(4); + private TileSet mCurrentTiles; /* package */TileSet mNewTiles; - private final float[] mBoxCoords = new float[8]; - public TileManager(MapView mapView) { + private final QuadTreeIndex mIndex = new QuadTreeIndex(){ + + @Override + public MapTile create(int x, int y, int z) { + QuadTree t = super.add(x, y, z); + t.item = new MapTile(x, y, (byte)z); + t.item.rel = t; + + return t.item; + } + + @Override + public void remove(MapTile t) { + if (t.rel == null) { + Log.d(TAG, "BUG already removed " + t); + return; + } + + super.remove(t.rel); + + t.rel.item = null; + t.rel = null; + } + }; + + private final float[] mBoxCoords = new float[8]; + private final TileLayer mTileLayer; + + public TileManager(MapView mapView, TileLayer tileLayer) { mMapView = mapView; + mTileLayer = tileLayer; + mMapViewPosition = mapView.getMapViewPosition(); mJobs = new ArrayList(); - mTiles = new MapTile[GLRenderer.CACHE_TILES]; + mTiles = new MapTile[CACHE_TILES_MAX]; mTilesSize = 0; mTilesForUpload = 0; @@ -119,7 +156,7 @@ public class TileManager { //} // clear cache index - QuadTree.init(); + //QuadTree.init(); // clear references to cached MapTiles Arrays.fill(mTiles, null); @@ -160,7 +197,7 @@ public class TileManager { // start with old jobs while new jobs are calculated, which // should increase the chance that they are free when new // jobs come in. - mMapView.addJobs(null); + mTileLayer.addJobs(null); // load some tiles more than currently visible (* 0.75) double scale = pos.scale * 0.9f; @@ -223,11 +260,11 @@ public class TileManager { updateTileDistances(jobs, jobs.length, pos); // sets tiles to state == LOADING - mMapView.addJobs(jobs); + mTileLayer.addJobs(jobs); mJobs.clear(); /* limit cache items */ - int remove = mTilesCount - GLRenderer.CACHE_TILES; + int remove = mTilesCount - CACHE_TILES_MAX; if (remove > CACHE_THRESHOLD || mTilesForUpload > MAX_TILES_IN_QUEUE) @@ -235,9 +272,13 @@ public class TileManager { limitCache(pos, remove); } - // need to keep track of TileSets to clear on reset... - private static ArrayList mTileSets = new ArrayList(2); + /** + * Retrive a TileSet of current tiles. + * Tiles remain locked in cache until the set is unlocked by either passing + * it again to this function or to releaseTiles. If passed TileSet is null + * it will be allocated. + */ public TileSet getActiveTiles(TileSet td) { if (mCurrentTiles == null) return td; @@ -287,11 +328,11 @@ public class TileManager { /* package */MapTile addTile(int x, int y, int zoomLevel) { MapTile tile; - tile = QuadTree.getTile(x, y, zoomLevel); + //tile = QuadTree.getTile(x, y, zoomLevel); + tile = mIndex.getTile(x, y, zoomLevel); if (tile == null) { - tile = new MapTile(x, y, (byte) zoomLevel); - QuadTree.add(tile); + tile = mIndex.create(x, y, zoomLevel); mJobs.add(tile); addToCache(tile); } else if (!tile.isActive()) { @@ -302,11 +343,11 @@ public class TileManager { boolean add = false; // prefetch parent - MapTile p = tile.rel.parent.tile; + MapTile p = tile.rel.parent.item; if (p == null) { - p = new MapTile(x >> 1, y >> 1, (byte) (zoomLevel - 1)); - QuadTree.add(p); + p = mIndex.create(x >> 1, y >> 1, zoomLevel - 1); + addToCache(p); add = true; } @@ -319,11 +360,10 @@ public class TileManager { if (zoomLevel > 3) { // prefetch grand parent - p = tile.rel.parent.parent.tile; + p = tile.rel.parent.parent.item; add = false; if (p == null) { - p = new MapTile(x >> 2, y >> 2, (byte) (zoomLevel - 2)); - QuadTree.add(p); + p = mIndex.create(x >> 2, y >> 2, zoomLevel - 2); addToCache(p); add = true; } @@ -376,7 +416,9 @@ public class TileManager { TextItem.pool.releaseAll(t.labels); - QuadTree.remove(t); + mIndex.remove(t); + + //QuadTree.remove(t); t.state = STATE_NONE; mTilesCount--; @@ -555,7 +597,7 @@ public class TileManager { private final ScanBox mScanBox = new ScanBox() { @Override - public void setVisible(int y, int x1, int x2) { + protected void setVisible(int y, int x1, int x2) { MapTile[] tiles = mNewTiles.tiles; int cnt = mNewTiles.cnt; int maxTiles = tiles.length; diff --git a/src/org/oscim/layers/tile/TileRenderLayer.java b/src/org/oscim/layers/tile/TileRenderLayer.java new file mode 100644 index 00000000..ba200eed --- /dev/null +++ b/src/org/oscim/layers/tile/TileRenderLayer.java @@ -0,0 +1,310 @@ +/* + * Copyright 2013 Hannes Janetzek + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . + */ +package org.oscim.layers.tile; + +import static org.oscim.layers.tile.JobTile.STATE_NEW_DATA; +import static org.oscim.layers.tile.JobTile.STATE_READY; + +import org.oscim.core.MapPosition; +import org.oscim.renderer.BufferObject; +import org.oscim.renderer.GLRenderer; +import org.oscim.renderer.GLRenderer.Matrices; +import org.oscim.renderer.ScanBox; +import org.oscim.renderer.overlays.RenderOverlay; +import org.oscim.view.MapView; + +import android.util.Log; +public class TileRenderLayer extends RenderOverlay { + private final static String TAG = TileRenderLayer.class.getName(); + + private final float[] mBoxCoords; + private final TileManager mTileManager; + public TileRenderLayer(MapView mapView, TileManager tileManager) { + super(mapView); + mTileManager = tileManager; + mBoxCoords = new float[8]; + } + + @Override + public void update(MapPosition curPos, boolean positionChanged, boolean tilesChanged, + Matrices matrices) { + int serial = 0; + + mMapPosition.copy(curPos); + + if (mDrawTiles != null) + serial = mDrawTiles.getSerial(); + + synchronized (tilelock) { + // get current tiles to draw + mDrawTiles = mTileManager.getActiveTiles(mDrawTiles); + } + + if (mDrawTiles == null || mDrawTiles.cnt == 0) + return; + + if (positionChanged) + mMapView.getMapViewPosition().getMapViewProjection(mBoxCoords); + + boolean changed = false; + //boolean positionChanged = false; + + // check if the tiles have changed... + if (serial != mDrawTiles.getSerial()) { + changed = true; + // FIXME needed? + //positionChanged = true; + } + + int tileCnt = mDrawTiles.cnt; + MapTile[] tiles = mDrawTiles.tiles; + + if (changed || positionChanged) + updateTileVisibility(); + + tileCnt += mNumTileHolder; + + /* prepare tile for rendering */ + int uploadCnt = compileTileLayers(tiles, tileCnt); + + tilesChanged |= (uploadCnt > 0); + + TileRenderer.draw(tiles, tileCnt, curPos, matrices); + } + + @Override + public void compile() { + + } + + @Override + public void render(MapPosition pos, Matrices m) { + + + } + + /** compile tile layer data and upload to VBOs */ + private static int compileTileLayers(MapTile[] tiles, int tileCnt) { + int uploadCnt = 0; + + for (int i = 0; i < tileCnt; i++) { + MapTile tile = tiles[i]; + + if (!tile.isVisible) + continue; + + if (tile.state == STATE_READY) + continue; + + if (tile.state == STATE_NEW_DATA) { + uploadTileData(tile); + continue; + } + + if (tile.holder != null) { + // load tile that is referenced by this holder + if (tile.holder.state == STATE_NEW_DATA) + uploadTileData(tile.holder); + + tile.state = tile.holder.state; + continue; + } + + // check near relatives than can serve as proxy + if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { + MapTile rel = tile.rel.parent.item; + if (rel.state == STATE_NEW_DATA) + uploadTileData(rel); + + // dont load child proxies + continue; + } + + for (int c = 0; c < 4; c++) { + if ((tile.proxies & 1 << c) == 0) + continue; + + MapTile rel = tile.rel.get(i); + if (rel != null && rel.state == STATE_NEW_DATA) + uploadTileData(rel); + } + } + + if (uploadCnt > 0) + GLRenderer.checkBufferUsage(false); + + return uploadCnt; + } + + private static void uploadTileData(MapTile tile) { + tile.state = STATE_READY; + + if (tile.layers == null) + return; + + int newSize = tile.layers.getSize(); + if (newSize > 0) { + + if (tile.layers.vbo == null) + tile.layers.vbo = BufferObject.get(newSize); + + if (!GLRenderer.uploadLayers(tile.layers, newSize, true)) { + Log.d(TAG, "BUG uploadTileData " + tile + " failed!"); + + BufferObject.release(tile.layers.vbo); + tile.layers.vbo = null; + tile.layers.clear(); + tile.layers = null; + } + } + } + + private final Object tilelock = new Object(); + + /** set tile isVisible flag true for tiles that intersect view */ + private void updateTileVisibility() { + + // lock tiles while updating isVisible state + synchronized (tilelock) { + MapPosition pos = mMapPosition; + MapTile[] tiles = mDrawTiles.tiles; + + int tileZoom = tiles[0].zoomLevel; + + for (int i = 0; i < mDrawTiles.cnt; i++) + tiles[i].isVisible = false; + + // count placeholder tiles + mNumTileHolder = 0; + + // check visibile tiles + mScanBox.scan(pos.x, pos.y, pos.scale, tileZoom, mBoxCoords); + } + } + + // get a TileSet of currently visible tiles + public TileSet getVisibleTiles(TileSet td) { + if (mDrawTiles == null) + return td; + + // ensure tiles keep visible state + synchronized (tilelock) { + + MapTile[] newTiles = mDrawTiles.tiles; + int cnt = mDrawTiles.cnt; + + if (td == null) + td = new TileSet(newTiles.length); + + // unlock previous tiles + for (int i = 0; i < td.cnt; i++) + td.tiles[i].unlock(); + + // lock tiles to not be removed from cache + td.cnt = 0; + for (int i = 0; i < cnt; i++) { + MapTile t = newTiles[i]; + if (t.isVisible && t.state == STATE_READY) { + t.lock(); + td.tiles[td.cnt++] = t; + } + } + } + return td; + } + + public void releaseTiles(TileSet td) { + for (int i = 0; i < td.cnt; i++) { + td.tiles[i].unlock(); + td.tiles[i] = null; + } + td.cnt = 0; + } + + + // Add additional tiles that serve as placeholer when flipping + // over date-line. + // I dont really like this but cannot think of a better solution: + // the other option would be to run scanbox each time for upload, + // drawing, proxies and text layer. needing to add placeholder only + // happens rarely, unless you live on Fidschi + + /* package */int mNumTileHolder; + /* package */TileSet mDrawTiles; + + // scanline fill class used to check tile visibility + private final ScanBox mScanBox = new ScanBox() { + @Override + protected 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. a little too complicated... + for (int x = x1; x < x2; x++) { + MapTile holder = null; + MapTile tile = null; + boolean found = false; + + if (x >= 0 && x < xmax) + continue; + + int xx = x; + if (x < 0) + xx = xmax + x; + else + xx = x - xmax; + + if (xx < 0 || xx >= xmax) + continue; + + for (int i = cnt; i < cnt + mNumTileHolder; 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; + + holder = new MapTile(x, y, (byte) mZoom); + holder.isVisible = true; + holder.holder = tile; + tile.isVisible = true; + tiles[cnt + mNumTileHolder++] = holder; + } + } + }; +} diff --git a/src/org/oscim/renderer/TileRenderer.java b/src/org/oscim/layers/tile/TileRenderer.java similarity index 91% rename from src/org/oscim/renderer/TileRenderer.java rename to src/org/oscim/layers/tile/TileRenderer.java index fcd0944a..2c96a76d 100644 --- a/src/org/oscim/renderer/TileRenderer.java +++ b/src/org/oscim/layers/tile/TileRenderer.java @@ -12,18 +12,23 @@ * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see . */ -package org.oscim.renderer; +package org.oscim.layers.tile; import static android.opengl.GLES20.GL_ARRAY_BUFFER; import static android.opengl.GLES20.glStencilMask; -import static org.oscim.generator.JobTile.STATE_READY; +import static org.oscim.layers.tile.JobTile.STATE_READY; import org.oscim.core.MapPosition; import org.oscim.core.Tile; +import org.oscim.renderer.GLRenderer; import org.oscim.renderer.GLRenderer.Matrices; +import org.oscim.renderer.LineRenderer; +import org.oscim.renderer.LineTexRenderer; +import org.oscim.renderer.PolygonRenderer; import org.oscim.renderer.layer.Layer; import org.oscim.utils.FastMath; import org.oscim.utils.Matrix4; +import org.oscim.utils.quadtree.QuadTree; import android.opengl.GLES20; @@ -56,6 +61,8 @@ public class TileRenderer { // discard z projection from tilt mProjMatrix.setValue(10, 0); mProjMatrix.setValue(14, 0); + GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT); + //GLES20.GL_STENCIL_BUFFER_BIT); GLES20.glDepthFunc(GLES20.GL_LESS); @@ -188,7 +195,7 @@ public class TileRenderer { if ((tile.proxies & 1 << i) == 0) continue; - MapTile c = tile.rel.child[i].tile; + MapTile c = tile.rel.get(i); if (c.state == STATE_READY) { drawTile(c, pos); @@ -200,10 +207,9 @@ public class TileRenderer { // just FIXME! private static void drawProxyTile(MapTile tile, MapPosition pos, boolean parent, boolean preferParent) { - //int diff = pos.zoomLevel - tile.zoomLevel; - QuadTree r = tile.rel; - MapTile proxy; + QuadTree r = tile.rel; + MapTile proxy; if (!preferParent) { // prefer drawing children @@ -213,7 +219,7 @@ public class TileRenderer { if (parent) { // draw parent proxy if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { - proxy = r.parent.tile; + proxy = r.parent.item; if (proxy.state == STATE_READY) { //Log.d(TAG, "1. draw parent " + proxy); drawTile(proxy, pos); @@ -222,12 +228,12 @@ public class TileRenderer { } else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) { // check if parent was already drawn if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { - proxy = r.parent.tile; + proxy = r.parent.item; if (proxy.state == STATE_READY) return; } - proxy = r.parent.parent.tile; + proxy = r.parent.parent.item; if (proxy.state == STATE_READY) drawTile(proxy, pos); } @@ -235,7 +241,7 @@ public class TileRenderer { // prefer drawing parent if (parent) { if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { - proxy = r.parent.tile; + proxy = r.parent.item; if (proxy != null && proxy.state == STATE_READY) { //Log.d(TAG, "2. draw parent " + proxy); drawTile(proxy, pos); @@ -248,7 +254,7 @@ public class TileRenderer { } else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) { // check if parent was already drawn if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { - proxy = r.parent.tile; + proxy = r.parent.item; if (proxy.state == STATE_READY) return; } @@ -256,7 +262,7 @@ public class TileRenderer { if (drawProxyChild(tile, pos) > 0) return; - proxy = r.parent.parent.tile; + proxy = r.parent.parent.item; if (proxy.state == STATE_READY) drawTile(proxy, pos); } diff --git a/src/org/oscim/renderer/TileSet.java b/src/org/oscim/layers/tile/TileSet.java similarity index 93% rename from src/org/oscim/renderer/TileSet.java rename to src/org/oscim/layers/tile/TileSet.java index a24994f4..daa89cbd 100644 --- a/src/org/oscim/renderer/TileSet.java +++ b/src/org/oscim/layers/tile/TileSet.java @@ -12,10 +12,11 @@ * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see . */ -package org.oscim.renderer; +package org.oscim.layers.tile; import java.util.Comparator; + /** * use with TileManager.getActiveTiles(TileSet) to get the current tiles. tiles * are locked to not be modifed until getActiveTiles passes them back on a @@ -27,10 +28,14 @@ public final class TileSet { int serial; + public int getSerial(){ + return serial; + } + TileSet() { } - TileSet(int numTiles) { + public TileSet(int numTiles) { tiles = new MapTile[numTiles]; } diff --git a/src/org/oscim/generator/WayDecorator.java b/src/org/oscim/layers/tile/WayDecorator.java similarity index 98% rename from src/org/oscim/generator/WayDecorator.java rename to src/org/oscim/layers/tile/WayDecorator.java index 7d9d8368..c4b6e048 100644 --- a/src/org/oscim/generator/WayDecorator.java +++ b/src/org/oscim/layers/tile/WayDecorator.java @@ -13,10 +13,9 @@ * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see . */ -package org.oscim.generator; +package org.oscim.layers.tile; import org.oscim.core.Tile; -import org.oscim.renderer.MapTile; import org.oscim.renderer.layer.TextItem; import org.oscim.theme.renderinstruction.Text; import org.oscim.utils.GeometryUtils; diff --git a/src/org/oscim/overlay/BuildingOverlay.java b/src/org/oscim/overlay/BuildingOverlay.java index dbc013e0..b352532e 100644 --- a/src/org/oscim/overlay/BuildingOverlay.java +++ b/src/org/oscim/overlay/BuildingOverlay.java @@ -30,9 +30,9 @@ public class BuildingOverlay extends Overlay { final ExtrusionOverlay mExtLayer; - public BuildingOverlay(MapView mapView) { + public BuildingOverlay(MapView mapView, org.oscim.layers.tile.TileRenderLayer tileRenderLayer) { super(mapView); - mExtLayer = new ExtrusionOverlay(mapView); + mExtLayer = new ExtrusionOverlay(mapView, tileRenderLayer); mLayer = mExtLayer; } diff --git a/src/org/oscim/overlay/LabelingOverlay.java b/src/org/oscim/overlay/LabelingOverlay.java index 5dd7e36f..52057dba 100644 --- a/src/org/oscim/overlay/LabelingOverlay.java +++ b/src/org/oscim/overlay/LabelingOverlay.java @@ -14,6 +14,7 @@ */ package org.oscim.overlay; +import org.oscim.layers.tile.TileRenderLayer; import org.oscim.renderer.overlays.TextOverlay; import org.oscim.view.MapView; @@ -27,9 +28,9 @@ public class LabelingOverlay extends Overlay { private final static String TAG = LabelingOverlay.class.getName(); final TextOverlay mTextLayer; - public LabelingOverlay(MapView mapView) { + public LabelingOverlay(MapView mapView, TileRenderLayer tileRenderLayer) { super(mapView); - mTextLayer = new TextOverlay(mapView); + mTextLayer = new TextOverlay(mapView, tileRenderLayer); mLayer = mTextLayer; } diff --git a/src/org/oscim/overlay/Overlay.java b/src/org/oscim/overlay/Overlay.java index 0eb4a668..2286e6f8 100644 --- a/src/org/oscim/overlay/Overlay.java +++ b/src/org/oscim/overlay/Overlay.java @@ -16,14 +16,10 @@ package org.oscim.overlay; -import org.oscim.core.MapPosition; import org.oscim.core.PointF; -import org.oscim.renderer.overlays.RenderOverlay; +import org.oscim.layers.InputLayer; import org.oscim.view.MapView; -import android.view.KeyEvent; -import android.view.MotionEvent; - /** * Base class representing an overlay which may be displayed on top of a * {@link MapView}. To add an overlay, subclass this class, create an instance, @@ -34,85 +30,37 @@ import android.view.MotionEvent; * * @author Nicolas Gramlich */ -public abstract class Overlay { - - // =========================================================== - // Constants - // =========================================================== - - //private static AtomicInteger sOrdinal = new AtomicInteger(); - - // From Google Maps API - //protected static final float SHADOW_X_SKEW = -0.8999999761581421f; - //protected static final float SHADOW_Y_SCALE = 0.5f; - - // =========================================================== - // Fields - // =========================================================== - - private boolean mEnabled = true; - private boolean mReceiveEvents = true; - - protected final MapView mMapView; - - /** RenderOverlay used to draw this layer. To be implemented by sub-classes */ - protected RenderOverlay mLayer; - - public RenderOverlay getLayer() { - return mLayer; - } - - // =========================================================== - // Constructors - // =========================================================== +public abstract class Overlay extends InputLayer { public Overlay(MapView mapView) { - mMapView = mapView; - } - - // =========================================================== - // Getter & Setter - // =========================================================== - - /** - * Sets whether the Overlay is marked to be enabled. This setting does - * nothing by default, but should be checked before calling draw(). - * - * @param pEnabled - * ... - */ - public void setEnabled(boolean pEnabled) { - mEnabled = pEnabled; + super(mapView); } /** - * Specifies if the Overlay is marked to be enabled. This should be checked - * before calling draw(). + * TBD + * + * Interface definition for overlays that contain items that can be snapped + * to (for example, when the user invokes a zoom, this could be called + * allowing the user to snap the zoom to an interesting point.) * - * @return true if the Overlay is marked enabled, false otherwise */ - public boolean isEnabled() { - return mEnabled; - } + public interface Snappable { - /** - * Sets whether the Overlay is marked to be receive touch exents. - * - * @param pEnabled - * ... - */ - public void setEnableEvents(boolean pEnabled) { - mReceiveEvents = pEnabled; - } - - /** - * Specifies if the Overlay is marked to be enabled. This should be checked - * before calling draw(). - * - * @return true if the Overlay is marked enabled, false otherwise - */ - public boolean eventsEnabled() { - return mReceiveEvents; + /** + * Checks to see if the given x and y are close enough to an item + * resulting in snapping the current action (e.g. zoom) to the item. + * + * @param x + * The x in screen coordinates. + * @param y + * The y in screen coordinates. + * @param snapPoint + * To be filled with the the interesting point (in screen + * coordinates) that is closest to the given x and y. Can be + * untouched if not snapping. + * @return Whether or not to snap to the interesting point. + */ + boolean onSnapToItem(int x, int y, PointF snapPoint); } ///** @@ -139,256 +87,4 @@ public abstract class Overlay { //protected final static int getSafeMenuIdSequence(int count) { // return sOrdinal.getAndAdd(count); //} - - // =========================================================== - // Methods - // =========================================================== - - /** - * Called before each frame render request. - * - * @param mapPosition - * current MapPosition - * @param changed - * true when MapPosition has changed since last call - */ - public void onUpdate(MapPosition mapPosition, boolean changed) { - - } - - /** - * Override to perform clean up of resources before shutdown. By default - * does nothing. - */ - public void onDetach() { - // FIXME call to this function is not implemented - } - - /** - * By default does nothing (return false). If you handled the - * Event, return true, otherwise return false. If - * you returned true none of the following Overlays or the - * underlying {@link MapView} has the chance to handle this event. - * - * @param keyCode - * ... - * @param event - * ... - * @return ... - */ - public boolean onKeyDown(int keyCode, KeyEvent event) { - return false; - } - - /** - * By default does nothing (return false). If you handled the - * Event, return true, otherwise return false. If - * you returned true none of the following Overlays or the - * underlying {@link MapView} has the chance to handle this event. - * - * @param keyCode - * ... - * @param event - * ... - * @return ... - */ - public boolean onKeyUp(int keyCode, KeyEvent event) { - return false; - } - - /** - * You can prevent all(!) other Touch-related events from happening!
- * By default does nothing (return false). If you handled the - * Event, return true, otherwise return false. If - * you returned true none of the following Overlays or the - * underlying {@link MapView} has the chance to handle this event. - * - * @param e - * ... - * @return ... - */ - public boolean onTouchEvent(MotionEvent e) { - return false; - } - - /** - * By default does nothing (return false). If you handled the - * Event, return true, otherwise return false. If - * you returned true none of the following Overlays or the - * underlying {@link MapView} has the chance to handle this event. - * - * @param e - * ... - * @return ... - */ - public boolean onTrackballEvent(MotionEvent e) { - return false; - } - - /** GestureDetector.OnDoubleTapListener **/ - - /** - * By default does nothing (return false). If you handled the - * Event, return true, otherwise return false. If - * you returned true none of the following Overlays or the - * underlying {@link MapView} has the chance to handle this event. - * - * @param e - * ... - * @return ... - */ - public boolean onDoubleTap(MotionEvent e) { - return false; - } - - /** - * By default does nothing (return false). If you handled the - * Event, return true, otherwise return false. If - * you returned true none of the following Overlays or the - * underlying {@link MapView} has the chance to handle this event. - * - * @param e - * ... - * @return ... - */ - public boolean onDoubleTapEvent(MotionEvent e) { - return false; - } - - /** - * By default does nothing (return false). If you handled the - * Event, return true, otherwise return false. If - * you returned true none of the following Overlays or the - * underlying {@link MapView} has the chance to handle this event. - * - * @param e - * ... - * @return ... - */ - public boolean onSingleTapConfirmed(MotionEvent e) { - return false; - } - - /** OnGestureListener **/ - - /** - * By default does nothing (return false). If you handled the - * Event, return true, otherwise return false. If - * you returned true none of the following Overlays or the - * underlying {@link MapView} has the chance to handle this event. - * - * @param e - * ... - * @return ... - */ - public boolean onDown(MotionEvent e) { - return false; - } - - /** - * By default does nothing (return false). If you handled the - * Event, return true, otherwise return false. If - * you returned true none of the following Overlays or the - * underlying {@link MapView} has the chance to handle this event. - * - * @param pEvent1 - * ... - * @param pEvent2 - * ... - * @param pVelocityX - * ... - * @param pVelocityY - * ... - * @return ... - */ - public boolean onFling(MotionEvent pEvent1, MotionEvent pEvent2, - float pVelocityX, float pVelocityY) { - return false; - } - - /** - * By default does nothing (return false). If you handled the - * Event, return true, otherwise return false. If - * you returned true none of the following Overlays or the - * underlying {@link MapView} has the chance to handle this event. - * - * @param e - * ... - * @return ... - */ - public boolean onLongPress(MotionEvent e) { - return false; - } - - /** - * By default does nothing (return false). If you handled the - * Event, return true, otherwise return false. If - * you returned true none of the following Overlays or the - * underlying {@link MapView} has the chance to handle this event. - * - * @param pEvent1 - * ... - * @param pEvent2 - * ... - * @param pDistanceX - * ... - * @param pDistanceY - * ... - * @return ... - */ - public boolean onScroll(MotionEvent pEvent1, MotionEvent pEvent2, - float pDistanceX, float pDistanceY) { - return false; - } - - /** - * @param pEvent - * ... - */ - public void onShowPress(MotionEvent pEvent) { - return; - } - - /** - * By default does nothing (return false). If you handled the - * Event, return true, otherwise return false. If - * you returned true none of the following Overlays or the - * underlying {@link MapView} has the chance to handle this event. - * - * @param e - * ... - * @return ... - */ - public boolean onSingleTapUp(MotionEvent e) { - return false; - } - - // =========================================================== - // Inner and Anonymous Classes - // =========================================================== - - /** - * Interface definition for overlays that contain items that can be snapped - * to (for example, when the user invokes a zoom, this could be called - * allowing the user to snap the zoom to an interesting point.) - */ - public interface Snappable { - - /** - * Checks to see if the given x and y are close enough to an item - * resulting in snapping the current action (e.g. zoom) to the item. - * - * @param x - * The x in screen coordinates. - * @param y - * The y in screen coordinates. - * @param snapPoint - * To be filled with the the interesting point (in screen - * coordinates) that is closest to the given x and y. Can be - * untouched if not snapping. - * @return Whether or not to snap to the interesting point. - */ - boolean onSnapToItem(int x, int y, PointF snapPoint); - } - } diff --git a/src/org/oscim/overlay/PathOverlay.java b/src/org/oscim/overlay/PathOverlay.java index d2049205..96764063 100644 --- a/src/org/oscim/overlay/PathOverlay.java +++ b/src/org/oscim/overlay/PathOverlay.java @@ -25,6 +25,7 @@ import org.oscim.core.MercatorProjection; import org.oscim.core.PointD; import org.oscim.core.Tile; import org.oscim.graphics.Paint.Cap; +import org.oscim.layers.Layer; import org.oscim.renderer.GLRenderer.Matrices; import org.oscim.renderer.layer.LineLayer; import org.oscim.renderer.overlays.BasicOverlay; @@ -34,7 +35,7 @@ import org.oscim.utils.LineClipper; import org.oscim.view.MapView; /** This class draws a path line in given color. */ -public class PathOverlay extends Overlay { +public class PathOverlay extends Layer { /** Stores points, converted to the map projection. */ /* package */protected final ArrayList mPoints; diff --git a/src/org/oscim/renderer/GLRenderer.java b/src/org/oscim/renderer/GLRenderer.java index 1a99b299..50448d2a 100644 --- a/src/org/oscim/renderer/GLRenderer.java +++ b/src/org/oscim/renderer/GLRenderer.java @@ -18,8 +18,6 @@ import static android.opengl.GLES20.GL_ARRAY_BUFFER; 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 org.oscim.generator.JobTile.STATE_NEW_DATA; -import static org.oscim.generator.JobTile.STATE_READY; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -31,6 +29,7 @@ import javax.microedition.khronos.opengles.GL10; import org.oscim.core.MapPosition; import org.oscim.core.Tile; +import org.oscim.layers.tile.MapTile; import org.oscim.renderer.layer.Layers; import org.oscim.renderer.layer.TextureItem; import org.oscim.renderer.overlays.RenderOverlay; @@ -62,7 +61,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { static int CACHE_TILES = CACHE_TILES_MAX; private static MapView mMapView; - static int screenWidth, screenHeight; + public static int screenWidth, screenHeight; private static MapViewPosition mMapViewPosition; private static MapPosition mMapPosition; @@ -76,6 +75,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { private static float[] mBoxCoords; public class Matrices { + // do not modify any of these public final Matrix4 viewproj = new Matrix4(); public final Matrix4 proj = new Matrix4(); public final Matrix4 view = new Matrix4(); @@ -89,88 +89,14 @@ public class GLRenderer implements GLSurfaceView.Renderer { //private static float[] mClearColor = null; - static int mQuadIndicesID; - final static int maxQuads = 64; + public static int mQuadIndicesID; + public final static int maxQuads = 64; private static boolean mUpdateColor = false; // drawlock to synchronize Main- and GL-Thread // static ReentrantLock tilelock = new ReentrantLock(); - static ReentrantLock drawlock = new ReentrantLock(); - - // Add additional tiles that serve as placeholer when flipping - // over date-line. - // I dont really like this but cannot think of a better solution: - // the other option would be to run scanbox each time for upload, - // drawing, proxies and text layer. needing to add placeholder only - // happens rarely, unless you live on Fidschi - - /* package */static int mNumTileHolder; - /* package */static TileSet mDrawTiles; - - // 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. a little too complicated... - for (int x = x1; x < x2; x++) { - MapTile holder = null; - MapTile tile = null; - boolean found = false; - - if (x >= 0 && x < xmax) - continue; - - int xx = x; - if (x < 0) - xx = xmax + x; - else - xx = x - xmax; - - if (xx < 0 || xx >= xmax) - continue; - - for (int i = cnt; i < cnt + mNumTileHolder; 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; - - holder = new MapTile(x, y, (byte) mZoom); - holder.isVisible = true; - holder.holder = tile; - tile.isVisible = true; - tiles[cnt + mNumTileHolder++] = holder; - } - } - }; + public static ReentrantLock drawlock = new ReentrantLock(); /** * @param mapView @@ -204,8 +130,6 @@ public class GLRenderer implements GLSurfaceView.Renderer { mUpdateColor = true; } - private static int uploadCnt = 0; - public static boolean uploadLayers(Layers layers, int newSize, boolean addFill) { @@ -258,7 +182,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { return true; } - private static void checkBufferUsage(boolean force) { + public static void checkBufferUsage(boolean force) { // try to clear some unused vbo when exceding limit if (!force && mBufferMemoryUsage < LIMIT_BUFFERS) { @@ -300,100 +224,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { } } - private static Object tilelock = new Object(); - /** set tile isVisible flag true for tiles that intersect view */ - private static void updateTileVisibility() { - MapPosition pos = mMapPosition; - MapTile[] tiles = mDrawTiles.tiles; - - // lock tiles while updating isVisible state - synchronized (GLRenderer.tilelock) { - int tileZoom = tiles[0].zoomLevel; - - for (int i = 0; i < mDrawTiles.cnt; i++) - tiles[i].isVisible = false; - - // count placeholder tiles - mNumTileHolder = 0; - - // check visibile tiles - mScanBox.scan(pos.x, pos.y, pos.scale, tileZoom, mBoxCoords); - } - } - - private static void uploadTileData(MapTile tile) { - tile.state = STATE_READY; - - if (tile.layers == null) - return; - - int newSize = tile.layers.getSize(); - if (newSize > 0) { - - if (tile.layers.vbo == null) - tile.layers.vbo = BufferObject.get(newSize); - - if (!uploadLayers(tile.layers, newSize, true)) { - Log.d(TAG, "BUG uploadTileData " + tile + " failed!"); - - BufferObject.release(tile.layers.vbo); - tile.layers.vbo = null; - tile.layers.clear(); - tile.layers = null; - } - } - } - - /** compile tile layer data and upload to VBOs */ - private static void compileTileLayers(MapTile[] tiles, int tileCnt) { - uploadCnt = 0; - for (int i = 0; i < tileCnt; i++) { - MapTile tile = tiles[i]; - - if (!tile.isVisible) - continue; - - if (tile.state == STATE_READY) - continue; - - if (tile.state == STATE_NEW_DATA) { - uploadTileData(tile); - continue; - } - - if (tile.holder != null) { - // load tile that is referenced by this holder - if (tile.holder.state == STATE_NEW_DATA) - uploadTileData(tile.holder); - - tile.state = tile.holder.state; - continue; - } - - // check near relatives than can serve as proxy - if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { - MapTile rel = tile.rel.parent.tile; - if (rel.state == STATE_NEW_DATA) - uploadTileData(rel); - - // dont load child proxies - continue; - } - - for (int c = 0; c < 4; c++) { - if ((tile.proxies & 1 << c) == 0) - continue; - - MapTile rel = tile.rel.child[c].tile; - if (rel != null && rel.state == STATE_NEW_DATA) - uploadTileData(rel); - } - } - - if (uploadCnt > 0) - checkBufferUsage(false); - } private static void draw() { long start = 0; @@ -407,35 +238,14 @@ public class GLRenderer implements GLSurfaceView.Renderer { mUpdateColor = false; } - // 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 - // or for a better reason see OpenGL Insights chapter 23. GLES20.glDepthMask(true); GLES20.glStencilMask(0xFF); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT); - int serial = 0; - if (mDrawTiles != null) - serial = mDrawTiles.serial; - - // get current tiles to draw - mDrawTiles = mMapView.getTileManager().getActiveTiles(mDrawTiles); - - if (mDrawTiles == null || mDrawTiles.cnt == 0) - return; - - boolean tilesChanged = false; - boolean positionChanged = false; - - // check if the tiles have changed... - if (serial != mDrawTiles.serial) { - tilesChanged = true; - // FIXME needed? - positionChanged = true; - } + boolean tilesChanged = true; + boolean positionChanged = true; // get current MapPosition, set mBoxCoords (mapping of screen to model // coordinates) @@ -457,38 +267,22 @@ public class GLRenderer implements GLSurfaceView.Renderer { } } - int tileCnt = mDrawTiles.cnt; - MapTile[] tiles = mDrawTiles.tiles; - - if (positionChanged) - updateTileVisibility(); - - tileCnt += mNumTileHolder; - - /* prepare tile for rendering */ - compileTileLayers(tiles, tileCnt); - - tilesChanged |= (uploadCnt > 0); - /* update overlays */ RenderOverlay[] overlays = mMapView.getOverlayManager().getRenderLayers(); for (int i = 0, n = overlays.length; i < n; i++) overlays[i].update(mMapPosition, positionChanged, tilesChanged, mMatrices); - /* draw base layer */ - TileRenderer.draw(tiles, tileCnt, pos, mMatrices); - /* draw overlays */ for (int i = 0, n = overlays.length; i < n; i++) { - RenderOverlay renderOverlay = overlays[i]; + RenderOverlay renderLayer = overlays[i]; - if (renderOverlay.newData) { - renderOverlay.compile(); - renderOverlay.newData = false; + if (renderLayer.newData) { + renderLayer.compile(); + renderLayer.newData = false; } - if (renderOverlay.isReady) - renderOverlay.render(mMapPosition, mMatrices); + if (renderLayer.isReady) + renderLayer.render(mMapPosition, mMatrices); } if (MapView.debugFrameTime) { @@ -506,44 +300,6 @@ public class GLRenderer implements GLSurfaceView.Renderer { return ((t.tileX % 4) + (t.tileY % 4 * 4) + 1); } - // get a TileSet of currently visible tiles - public static TileSet getVisibleTiles(TileSet td) { - if (mDrawTiles == null) - return td; - - // ensure tiles keep visible state - synchronized (GLRenderer.tilelock) { - MapTile[] newTiles = mDrawTiles.tiles; - int cnt = mDrawTiles.cnt; - - if (td == null) - td = new TileSet(newTiles.length); - - // unlock previous tiles - for (int i = 0; i < td.cnt; i++) - td.tiles[i].unlock(); - - // lock tiles to not be removed from cache - td.cnt = 0; - for (int i = 0; i < cnt; i++) { - MapTile t = newTiles[i]; - if (t.isVisible && t.state == STATE_READY) { - t.lock(); - td.tiles[td.cnt++] = t; - } - } - } - return td; - } - - public static void releaseTiles(TileSet td) { - for (int i = 0; i < td.cnt; i++) { - td.tiles[i].unlock(); - td.tiles[i] = null; - } - td.cnt = 0; - } - @Override public void onSurfaceChanged(GL10 glUnused, int width, int height) { Log.d(TAG, "SurfaceChanged:" + mNewSurface + " " + width + "x" + height); @@ -608,7 +364,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0); mBufferMemoryUsage = 0; - mDrawTiles = null; + //mDrawTiles = null; int numTiles = (screenWidth / (Tile.SIZE / 2) + 2) * (screenHeight / (Tile.SIZE / 2) + 2); @@ -624,18 +380,21 @@ public class GLRenderer implements GLSurfaceView.Renderer { mMapView.redrawMap(true); } - - @Override - public void onSurfaceCreated(GL10 gl, EGLConfig config) { - // String ext = GLES20.glGetString(GLES20.GL_EXTENSIONS); - // Log.d(TAG, "Extensions: " + ext); - - // classes that require GL context for initialization + public static void initRenderer() { LineRenderer.init(); LineTexRenderer.init(); PolygonRenderer.init(); TextureRenderer.init(); + TextureItem.init(10); + } + + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + // Log.d(TAG, GLES20.glGetString(GLES20.GL_EXTENSIONS)); + + // classes that require GL context for initialization + initRenderer(); mNewSurface = true; } diff --git a/src/org/oscim/renderer/QuadTree.java b/src/org/oscim/renderer/QuadTree.java deleted file mode 100644 index a3cf0ca3..00000000 --- a/src/org/oscim/renderer/QuadTree.java +++ /dev/null @@ -1,148 +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 . - */ -package org.oscim.renderer; - -import android.util.Log; - -public class QuadTree { - private static String TAG = QuadTree.class.getName(); - - // pointer to tile 0/0/0 - private static QuadTree root; - - // parent pointer is used to link pool items - private static QuadTree pool; - - public QuadTree parent; - // .... x y - // 0 => 0 0 - // 1 => 1 0 - // 2 => 0 1 - // 3 => 1 1 - public final QuadTree[] child = new QuadTree[4]; - int refs = 0; - byte id; - public MapTile tile; - - static void init() { - pool = null; - root = new QuadTree(); - root.parent = root; - } - - static boolean remove(MapTile t) { - if (t.rel == null) { - // Bad Things(tm) happened - Log.d(TAG, "BUG already removed " + t); - return true; - } - - QuadTree cur = t.rel; - QuadTree next; - - for (; cur != root;) { - // keep pointer to parent - next = cur.parent; - cur.refs--; - - // if current node has no children - if (cur.refs == 0) { - // unhook from parent - next.child[cur.id] = null; - - // add item back to pool - cur.parent = pool; - pool = cur; - } - cur = next; - } - - root.refs--; - - t.rel.tile = null; - t.rel = null; - - return true; - } - - static QuadTree add(MapTile tile) { - - int x = tile.tileX; - int y = tile.tileY; - int z = tile.zoomLevel; - - // if (x < 0 || x >= 1 << z) { - // Log.d(TAG, "invalid position"); - // return null; - // } - // if (y < 0 || y >= 1 << z) { - // Log.d(TAG, "invalid position"); - // return null; - // } - - QuadTree leaf = root; - - for (int level = z - 1; level >= 0; level--) { - - int id = ((x >> level) & 1) | ((y >> level) & 1) << 1; - - leaf.refs++; - - QuadTree cur = leaf.child[id]; - - if (cur != null) { - leaf = cur; - continue; - } - - if (pool != null) { - cur = pool; - pool = pool.parent; - } else { - cur = new QuadTree(); - } - - cur.refs = 0; - cur.id = (byte) id; - cur.parent = leaf; - cur.parent.child[id] = cur; - - leaf = cur; - } - - leaf.refs++; - leaf.tile = tile; - tile.rel = leaf; - - return leaf; - } - - static MapTile getTile(int x, int y, int z) { - QuadTree leaf = root; - - for (int level = z - 1; level >= 0; level--) { - - leaf = leaf.child[((x >> level) & 1) | ((y >> level) & 1) << 1]; - - if (leaf == null) - return null; - - if (level == 0) { - return leaf.tile; - } - } - return null; - } -} diff --git a/src/org/oscim/renderer/ScanBox.java b/src/org/oscim/renderer/ScanBox.java index dacc4a8f..a1ac087b 100644 --- a/src/org/oscim/renderer/ScanBox.java +++ b/src/org/oscim/renderer/ScanBox.java @@ -78,7 +78,7 @@ public abstract class ScanBox { protected int mZoom; - abstract void setVisible(int y, int x1, int x2); + protected abstract void setVisible(int y, int x1, int x2); public void scan(double x, double y, double scale, int zoom, float[] box) { mZoom = zoom; diff --git a/src/org/oscim/renderer/overlays/ExtrusionOverlay.java b/src/org/oscim/renderer/overlays/ExtrusionOverlay.java index 668a3cd1..9ae4701b 100644 --- a/src/org/oscim/renderer/overlays/ExtrusionOverlay.java +++ b/src/org/oscim/renderer/overlays/ExtrusionOverlay.java @@ -20,12 +20,13 @@ import java.nio.ShortBuffer; import org.oscim.core.MapPosition; import org.oscim.core.Tile; -import org.oscim.generator.JobTile; +import org.oscim.layers.tile.JobTile; +import org.oscim.layers.tile.MapTile; +import org.oscim.layers.tile.TileRenderLayer; +import org.oscim.layers.tile.TileSet; import org.oscim.renderer.GLRenderer; import org.oscim.renderer.GLRenderer.Matrices; import org.oscim.renderer.GLState; -import org.oscim.renderer.MapTile; -import org.oscim.renderer.TileSet; import org.oscim.renderer.layer.ExtrusionLayer; import org.oscim.utils.GlUtils; import org.oscim.view.MapView; @@ -39,8 +40,11 @@ import android.util.Log; public class ExtrusionOverlay extends RenderOverlay { private final static String TAG = ExtrusionOverlay.class.getName(); - public ExtrusionOverlay(MapView mapView) { + private final TileRenderLayer mTileLayer; + + public ExtrusionOverlay(MapView mapView, org.oscim.layers.tile.TileRenderLayer tileRenderLayer) { super(mapView); + mTileLayer = tileRenderLayer; } private static int[] shaderProgram = new int[2]; @@ -92,7 +96,10 @@ public class ExtrusionOverlay extends RenderOverlay { } int ready = 0; - mTileSet = mMapView.getTileManager().getActiveTiles(mTileSet); + mTileSet = mTileLayer.getVisibleTiles(mTileSet); + if (mTileSet == null) + return; + MapTile[] tiles = mTileSet.tiles; // FIXME just release tiles in this case if (mAlpha == 0 || curPos.zoomLevel < 16) { @@ -135,11 +142,12 @@ public class ExtrusionOverlay extends RenderOverlay { for (int i = 0; i < mTileSet.cnt; i++) { if (!tiles[i].isVisible) continue; + MapTile t = tiles[i]; for (byte j = 0; j < 4; j++) { if ((t.proxies & (1 << j)) != 0) { - MapTile c = t.rel.child[j].tile; + MapTile c = t.rel.get(j); el = getLayer(c); if (el == null || !el.compiled) diff --git a/src/org/oscim/renderer/overlays/TextOverlay.java b/src/org/oscim/renderer/overlays/TextOverlay.java index f99fe460..25ada767 100644 --- a/src/org/oscim/renderer/overlays/TextOverlay.java +++ b/src/org/oscim/renderer/overlays/TextOverlay.java @@ -32,18 +32,19 @@ import java.util.HashMap; import org.oscim.core.MapPosition; import org.oscim.core.Tile; -import org.oscim.generator.JobTile; import org.oscim.graphics.Color; import org.oscim.graphics.Paint.Cap; +import org.oscim.layers.tile.JobTile; +import org.oscim.layers.tile.MapTile; +import org.oscim.layers.tile.TileRenderLayer; +import org.oscim.layers.tile.TileSet; import org.oscim.renderer.BufferObject; import org.oscim.renderer.GLRenderer; import org.oscim.renderer.GLRenderer.Matrices; import org.oscim.renderer.GLState; import org.oscim.renderer.LineRenderer; -import org.oscim.renderer.MapTile; import org.oscim.renderer.PolygonRenderer; import org.oscim.renderer.TextureRenderer; -import org.oscim.renderer.TileSet; import org.oscim.renderer.layer.Layer; import org.oscim.renderer.layer.Layers; import org.oscim.renderer.layer.LineLayer; @@ -199,11 +200,13 @@ public class TextOverlay extends BasicOverlay { private float mSquareRadius; private int mRelabelCnt; + private final TileRenderLayer mTileLayer; - public TextOverlay(MapView mapView) { + public TextOverlay(MapView mapView, TileRenderLayer baseLayer) { super(mapView); - mMapViewPosition = mapView.getMapViewPosition(); + mMapViewPosition = mapView.getMapViewPosition(); + mTileLayer = baseLayer; layers.textureLayers = new TextLayer(); mTmpLayer = new TextLayer(); mActiveTiles = new HashMap(); @@ -350,7 +353,9 @@ public class TextOverlay extends BasicOverlay { return false; // get current tiles - mTileSet = GLRenderer.getVisibleTiles(mTileSet); + mTileSet = mTileLayer.getVisibleTiles(mTileSet); + if (mTileSet == null) + return false; if (mTileSet.cnt == 0) return false; @@ -605,7 +610,7 @@ public class TextOverlay extends BasicOverlay { tl.labels = null; // remove tile locks - GLRenderer.releaseTiles(mTileSet); + mTileLayer.releaseTiles(mTileSet); // pass new labels for rendering synchronized (this) { diff --git a/src/org/oscim/theme/RenderThemeHandler.java b/src/org/oscim/theme/RenderThemeHandler.java index f71e9e6f..0196f6b5 100644 --- a/src/org/oscim/theme/RenderThemeHandler.java +++ b/src/org/oscim/theme/RenderThemeHandler.java @@ -117,6 +117,8 @@ public class RenderThemeHandler extends DefaultHandler { private int mLevel; private RenderTheme mRenderTheme; private final Stack mRuleStack = new Stack(); + private final HashMap tmpStyleHash = + new HashMap(10); @Override public void endDocument() { @@ -148,8 +150,6 @@ public class RenderThemeHandler extends DefaultHandler { Log.d(TAG, exception.getMessage()); } - private static HashMap tmpStyleHash = - new HashMap(10); @Override public void startElement(String uri, String localName, String qName, diff --git a/src/org/oscim/view/LayerManager.java b/src/org/oscim/view/LayerManager.java index 005e8e6d..c81b8b31 100644 --- a/src/org/oscim/view/LayerManager.java +++ b/src/org/oscim/view/LayerManager.java @@ -21,7 +21,8 @@ import java.util.concurrent.CopyOnWriteArrayList; import org.oscim.core.MapPosition; import org.oscim.core.PointF; -import org.oscim.overlay.Overlay; +import org.oscim.layers.InputLayer; +import org.oscim.layers.Layer; import org.oscim.overlay.Overlay.Snappable; import org.oscim.renderer.overlays.RenderOverlay; @@ -32,45 +33,45 @@ import android.view.GestureDetector.OnGestureListener; import android.view.KeyEvent; import android.view.MotionEvent; -public class LayerManager extends AbstractList implements OnGestureListener, +public class LayerManager extends AbstractList implements OnGestureListener, OnDoubleTapListener { private final GestureDetector mGestureDetector; - private final CopyOnWriteArrayList mOverlayList; + private final CopyOnWriteArrayList mLayerList; LayerManager(Context context) { - mOverlayList = new CopyOnWriteArrayList(); + mLayerList = new CopyOnWriteArrayList(); mGestureDetector = new GestureDetector(context, this); mGestureDetector.setOnDoubleTapListener(this); } @Override - public synchronized Overlay get(final int pIndex) { - return mOverlayList.get(pIndex); + public synchronized Layer get(final int pIndex) { + return mLayerList.get(pIndex); } @Override public synchronized int size() { - return mOverlayList.size(); + return mLayerList.size(); } @Override - public synchronized void add(final int pIndex, final Overlay pElement) { - mOverlayList.add(pIndex, pElement); - mDirtyOverlays = true; + public synchronized void add(final int pIndex, final Layer pElement) { + mLayerList.add(pIndex, pElement); + mDirtyLayers = true; } @Override - public synchronized Overlay remove(final int pIndex) { - mDirtyOverlays = true; - return mOverlayList.remove(pIndex); + public synchronized Layer remove(final int pIndex) { + mDirtyLayers = true; + return mLayerList.remove(pIndex); } @Override - public synchronized Overlay set(final int pIndex, final Overlay pElement) { - mDirtyOverlays = true; - return mOverlayList.set(pIndex, pElement); + public synchronized Layer set(final int pIndex, final Layer pElement) { + mDirtyLayers = true; + return mLayerList.set(pIndex, pElement); } public boolean handleMotionEvent(MotionEvent e) { @@ -84,59 +85,68 @@ public class LayerManager extends AbstractList implements OnGestureList return false; } - private boolean mDirtyOverlays; + private boolean mDirtyLayers; private RenderOverlay[] mDrawLayers; public RenderOverlay[] getRenderLayers() { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); return mDrawLayers; } public void onDetach() { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (Layer o : mLayers) o.onDetach(); } - Overlay[] mOverlays; + Layer[] mLayers; + InputLayer[] mInputLayer; - private synchronized void updateOverlays() { - if (!mDirtyOverlays) + private synchronized void updateLayers() { + if (!mDirtyLayers) return; - mOverlays = new Overlay[mOverlayList.size()]; + mLayers = new Layer[mLayerList.size()]; int numRenderLayers = 0; + int numInputLayers = 0; - for (int i = 0, n = mOverlayList.size(); i < n; i++) { - Overlay o = mOverlayList.get(i); + for (int i = 0, n = mLayerList.size(); i < n; i++) { + Layer o = mLayerList.get(i); if (o.getLayer() != null) numRenderLayers++; - mOverlays[n - i - 1] = o; + if (o instanceof InputLayer) + numInputLayers++; + + mLayers[n - i - 1] = o; } mDrawLayers = new RenderOverlay[numRenderLayers]; + mInputLayer = new InputLayer[numInputLayers]; - for (int i = 0, cnt = 0, n = mOverlayList.size(); i < n; i++) { - Overlay o = mOverlayList.get(i); + for (int i = 0, cntR = 0, cntI = 0, n = mLayerList.size(); i < n; i++) { + Layer o = mLayerList.get(i); RenderOverlay l = o.getLayer(); if (l != null) - mDrawLayers[cnt++] = l; + mDrawLayers[cntR++] = l; + + if (o instanceof InputLayer) + mInputLayer[cntI++] = (InputLayer)o; } - mDirtyOverlays = false; + mDirtyLayers = false; } public boolean onTouchEvent(final MotionEvent event) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o.onTouchEvent(event)) return true; @@ -144,10 +154,10 @@ public class LayerManager extends AbstractList implements OnGestureList } public boolean onKeyDown(final int keyCode, final KeyEvent event) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o.onKeyDown(keyCode, event)) return true; @@ -155,10 +165,10 @@ public class LayerManager extends AbstractList implements OnGestureList } public boolean onKeyUp(final int keyCode, final KeyEvent event) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o.onKeyUp(keyCode, event)) return true; @@ -166,10 +176,10 @@ public class LayerManager extends AbstractList implements OnGestureList } public boolean onTrackballEvent(final MotionEvent event) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o.onTrackballEvent(event)) return true; @@ -177,10 +187,10 @@ public class LayerManager extends AbstractList implements OnGestureList } public boolean onSnapToItem(final int x, final int y, final PointF snapPoint) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o instanceof Snappable) if (((Snappable) o).onSnapToItem(x, y, snapPoint)) return true; @@ -192,10 +202,10 @@ public class LayerManager extends AbstractList implements OnGestureList @Override public boolean onDoubleTap(final MotionEvent e) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o.onDoubleTap(e)) return true; @@ -204,10 +214,10 @@ public class LayerManager extends AbstractList implements OnGestureList @Override public boolean onDoubleTapEvent(final MotionEvent e) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o.onDoubleTapEvent(e)) return true; @@ -216,10 +226,10 @@ public class LayerManager extends AbstractList implements OnGestureList @Override public boolean onSingleTapConfirmed(final MotionEvent e) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o.onSingleTapConfirmed(e)) return true; @@ -230,10 +240,10 @@ public class LayerManager extends AbstractList implements OnGestureList @Override public boolean onDown(final MotionEvent pEvent) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o.onDown(pEvent)) return true; @@ -243,10 +253,10 @@ public class LayerManager extends AbstractList implements OnGestureList @Override public boolean onFling(final MotionEvent pEvent1, final MotionEvent pEvent2, final float pVelocityX, final float pVelocityY) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o.onFling(pEvent1, pEvent2, pVelocityX, pVelocityY)) return true; @@ -255,10 +265,10 @@ public class LayerManager extends AbstractList implements OnGestureList @Override public void onLongPress(final MotionEvent pEvent) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o.onLongPress(pEvent)) return; } @@ -266,10 +276,10 @@ public class LayerManager extends AbstractList implements OnGestureList @Override public boolean onScroll(final MotionEvent pEvent1, final MotionEvent pEvent2, final float pDistanceX, final float pDistanceY) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o.onScroll(pEvent1, pEvent2, pDistanceX, pDistanceY)) return true; @@ -278,20 +288,20 @@ public class LayerManager extends AbstractList implements OnGestureList @Override public void onShowPress(final MotionEvent pEvent) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) o.onShowPress(pEvent); } @Override public boolean onSingleTapUp(final MotionEvent pEvent) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) + for (InputLayer o : mInputLayer) if (o.onSingleTapUp(pEvent)) return true; @@ -299,52 +309,62 @@ public class LayerManager extends AbstractList implements OnGestureList } public void onUpdate(MapPosition mapPosition, boolean changed) { - if (mDirtyOverlays) - updateOverlays(); + if (mDirtyLayers) + updateLayers(); - for (Overlay o : mOverlays) - o.onUpdate(mapPosition, changed); + for (Layer l : mLayers) + l.onUpdate(mapPosition, changed); } + public void destroy() { + if (mDirtyLayers) + updateLayers(); + + for (Layer l : mLayers){ + l.destroy(); + } + } + + // /** - // * Gets the optional TilesOverlay class. + // * Gets the optional TilesLayer class. // * - // * @return the tilesOverlay + // * @return the tilesLayer // */ - // public TilesOverlay getTilesOverlay() { - // return mTilesOverlay; + // public TilesLayer getTilesLayer() { + // return mTilesLayer; // } // // /** - // * Sets the optional TilesOverlay class. If set, this overlay will be + // * Sets the optional TilesLayer class. If set, this overlay will be // drawn before all other // * overlays and will not be included in the editable list of overlays and // can't be cleared - // * except by a subsequent call to setTilesOverlay(). + // * except by a subsequent call to setTilesLayer(). // * - // * @param tilesOverlay - // * the tilesOverlay to set + // * @param tilesLayer + // * the tilesLayer to set // */ - // public void setTilesOverlay(final TilesOverlay tilesOverlay) { - // mTilesOverlay = tilesOverlay; + // public void setTilesLayer(final TilesLayer tilesLayer) { + // mTilesLayer = tilesLayer; // } // public void onDraw(final Canvas c, final MapView pMapView) { - // // if ((mTilesOverlay != null) && mTilesOverlay.isEnabled()) { - // // mTilesOverlay.draw(c, pMapView, true); + // // if ((mTilesLayer != null) && mTilesLayer.isEnabled()) { + // // mTilesLayer.draw(c, pMapView, true); // // } // // - // // if ((mTilesOverlay != null) && mTilesOverlay.isEnabled()) { - // // mTilesOverlay.draw(c, pMapView, false); + // // if ((mTilesLayer != null) && mTilesLayer.isEnabled()) { + // // mTilesLayer.draw(c, pMapView, false); // // } // - // for (final Overlay overlay : mOverlayList) { + // for (final Layer overlay : mLayerList) { // if (overlay.isEnabled()) { // overlay.draw(c, pMapView, true); // } // } // - // for (final Overlay overlay : mOverlayList) { + // for (final Layer overlay : mLayerList) { // if (overlay.isEnabled()) { // overlay.draw(c, pMapView, false); // } @@ -355,10 +375,10 @@ public class LayerManager extends AbstractList implements OnGestureList // ** Options Menu **// // public void setOptionsMenusEnabled(final boolean pEnabled) { - // for (final Overlay overlay : mOverlayList) { - // if ((overlay instanceof IOverlayMenuProvider) - // && ((IOverlayMenuProvider) overlay).isOptionsMenuEnabled()) { - // ((IOverlayMenuProvider) overlay).setOptionsMenuEnabled(pEnabled); + // for (final Layer overlay : mLayerList) { + // if ((overlay instanceof ILayerMenuProvider) + // && ((ILayerMenuProvider) overlay).isOptionsMenuEnabled()) { + // ((ILayerMenuProvider) overlay).setOptionsMenuEnabled(pEnabled); // } // } // } @@ -367,19 +387,19 @@ public class LayerManager extends AbstractList implements OnGestureList // menuIdOffset, // final MapView mapView) { // boolean result = true; - // for (final Overlay overlay : this.overlaysReversed()) { - // if ((overlay instanceof IOverlayMenuProvider) - // && ((IOverlayMenuProvider) overlay).isOptionsMenuEnabled()) { - // result &= ((IOverlayMenuProvider) overlay).onCreateOptionsMenu(pMenu, + // for (final Layer overlay : this.overlaysReversed()) { + // if ((overlay instanceof ILayerMenuProvider) + // && ((ILayerMenuProvider) overlay).isOptionsMenuEnabled()) { + // result &= ((ILayerMenuProvider) overlay).onCreateOptionsMenu(pMenu, // menuIdOffset, // mapView); // } // } // - // if ((mTilesOverlay != null) && (mTilesOverlay instanceof - // IOverlayMenuProvider) - // && ((IOverlayMenuProvider) mTilesOverlay).isOptionsMenuEnabled()) { - // result &= mTilesOverlay.onCreateOptionsMenu(pMenu, menuIdOffset, + // if ((mTilesLayer != null) && (mTilesLayer instanceof + // ILayerMenuProvider) + // && ((ILayerMenuProvider) mTilesLayer).isOptionsMenuEnabled()) { + // result &= mTilesLayer.onCreateOptionsMenu(pMenu, menuIdOffset, // mapView); // } // @@ -389,18 +409,18 @@ public class LayerManager extends AbstractList implements OnGestureList // public boolean onPrepareOptionsMenu(final Menu pMenu, final int // menuIdOffset, // final MapView mapView) { - // for (final Overlay overlay : this.overlaysReversed()) { - // if ((overlay instanceof IOverlayMenuProvider) - // && ((IOverlayMenuProvider) overlay).isOptionsMenuEnabled()) { - // ((IOverlayMenuProvider) overlay).onPrepareOptionsMenu(pMenu, + // for (final Layer overlay : this.overlaysReversed()) { + // if ((overlay instanceof ILayerMenuProvider) + // && ((ILayerMenuProvider) overlay).isOptionsMenuEnabled()) { + // ((ILayerMenuProvider) overlay).onPrepareOptionsMenu(pMenu, // menuIdOffset, mapView); // } // } // - // if ((mTilesOverlay != null) && (mTilesOverlay instanceof - // IOverlayMenuProvider) - // && ((IOverlayMenuProvider) mTilesOverlay).isOptionsMenuEnabled()) { - // mTilesOverlay.onPrepareOptionsMenu(pMenu, menuIdOffset, mapView); + // if ((mTilesLayer != null) && (mTilesLayer instanceof + // ILayerMenuProvider) + // && ((ILayerMenuProvider) mTilesLayer).isOptionsMenuEnabled()) { + // mTilesLayer.onPrepareOptionsMenu(pMenu, menuIdOffset, mapView); // } // // return true; @@ -409,20 +429,20 @@ public class LayerManager extends AbstractList implements OnGestureList // public boolean onOptionsItemSelected(final MenuItem item, final int // menuIdOffset, // final MapView mapView) { - // for (final Overlay overlay : this.overlaysReversed()) { - // if ((overlay instanceof IOverlayMenuProvider) - // && ((IOverlayMenuProvider) overlay).isOptionsMenuEnabled() - // && ((IOverlayMenuProvider) overlay).onOptionsItemSelected(item, + // for (final Layer overlay : this.overlaysReversed()) { + // if ((overlay instanceof ILayerMenuProvider) + // && ((ILayerMenuProvider) overlay).isOptionsMenuEnabled() + // && ((ILayerMenuProvider) overlay).onOptionsItemSelected(item, // menuIdOffset, // mapView)) { // return true; // } // } // - // if ((mTilesOverlay != null) - // && (mTilesOverlay instanceof IOverlayMenuProvider) - // && ((IOverlayMenuProvider) mTilesOverlay).isOptionsMenuEnabled() - // && ((IOverlayMenuProvider) mTilesOverlay).onOptionsItemSelected(item, + // if ((mTilesLayer != null) + // && (mTilesLayer instanceof ILayerMenuProvider) + // && ((ILayerMenuProvider) mTilesLayer).isOptionsMenuEnabled() + // && ((ILayerMenuProvider) mTilesLayer).onOptionsItemSelected(item, // menuIdOffset, // mapView)) { // return true; diff --git a/src/org/oscim/view/MapActivity.java b/src/org/oscim/view/MapActivity.java index c5e57eae..71e7fbc1 100644 --- a/src/org/oscim/view/MapActivity.java +++ b/src/org/oscim/view/MapActivity.java @@ -14,11 +14,8 @@ */ package org.oscim.view; -import java.io.FileNotFoundException; - import org.oscim.core.GeoPoint; import org.oscim.core.MapPosition; -import org.oscim.theme.InternalRenderTheme; import android.app.Activity; import android.content.SharedPreferences; @@ -78,7 +75,7 @@ public abstract class MapActivity extends Activity { editor.putInt(KEY_LONGITUDE, geoPoint.longitudeE6); editor.putFloat(KEY_MAP_SCALE, (float)mapPosition.scale); - editor.putString(KEY_THEME, mMapView.getRenderTheme()); + //editor.putString(KEY_THEME, mMapView.getRenderTheme()); editor.commit(); } @@ -121,21 +118,21 @@ public abstract class MapActivity extends Activity { mMapView.getMapViewPosition().setMapPosition(mapPosition); } - String theme = sharedPreferences.getString(KEY_THEME, - InternalRenderTheme.DEFAULT.name()); + //String theme = sharedPreferences.getString(KEY_THEME, + // InternalRenderTheme.DEFAULT.name()); - if (theme.startsWith("/")) { - try { - mapView.setRenderTheme(theme); - } catch (FileNotFoundException e) { - mapView.setRenderTheme(InternalRenderTheme.DEFAULT); - } - } else { - try { - mapView.setRenderTheme(InternalRenderTheme.valueOf(theme)); - } catch (IllegalArgumentException e) { - mapView.setRenderTheme(InternalRenderTheme.DEFAULT); - } - } +// if (theme.startsWith("/")) { +// try { +// mapView.setRenderTheme(theme); +// } catch (FileNotFoundException e) { +// mapView.setRenderTheme(InternalRenderTheme.DEFAULT); +// } +// } else { +// try { +// mapView.setRenderTheme(InternalRenderTheme.valueOf(theme)); +// } catch (IllegalArgumentException e) { +// mapView.setRenderTheme(InternalRenderTheme.DEFAULT); +// } +// } } } diff --git a/src/org/oscim/view/MapView.java b/src/org/oscim/view/MapView.java index fed21340..5bc817b9 100644 --- a/src/org/oscim/view/MapView.java +++ b/src/org/oscim/view/MapView.java @@ -15,41 +15,21 @@ */ package org.oscim.view; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; import java.util.List; -import java.util.Map; - -import javax.xml.parsers.ParserConfigurationException; import org.oscim.core.BoundingBox; import org.oscim.core.GeoPoint; import org.oscim.core.MapPosition; import org.oscim.core.Tile; -import org.oscim.database.IMapDatabase; -import org.oscim.database.MapDatabaseFactory; -import org.oscim.database.MapDatabases; -import org.oscim.database.MapInfo; import org.oscim.database.MapOptions; -import org.oscim.database.OpenResult; -import org.oscim.generator.JobQueue; -import org.oscim.generator.JobTile; -import org.oscim.generator.MapWorker; -import org.oscim.generator.TileGenerator; +import org.oscim.layers.Layer; +import org.oscim.layers.tile.TileGenerator; +import org.oscim.layers.tile.TileLayer; import org.oscim.overlay.BuildingOverlay; import org.oscim.overlay.LabelingOverlay; import org.oscim.overlay.Overlay; -import org.oscim.renderer.GLRenderer; import org.oscim.renderer.GLView; -import org.oscim.renderer.TileManager; -import org.oscim.theme.ExternalRenderTheme; -import org.oscim.theme.InternalRenderTheme; -import org.oscim.theme.RenderTheme; -import org.oscim.theme.RenderThemeHandler; -import org.oscim.theme.Theme; import org.oscim.utils.AndroidUtils; -import org.xml.sax.SAXException; import android.content.Context; import android.util.AttributeSet; @@ -68,43 +48,28 @@ public class MapView extends RelativeLayout { public static final boolean debugFrameTime = false; public static final boolean testRegionZoom = false; - private static final boolean debugDatabase = false; public boolean mRotationEnabled = false; public boolean mCompassEnabled = false; public boolean enablePagedFling = false; + private final GLView mGLView; + + private final LayerManager mLayerManager; private final MapViewPosition mMapViewPosition; private final MapPosition mMapPosition; - //private final MapZoomControls mMapZoomControls; - private final Compass mCompass; - private final TileManager mTileManager; - private final LayerManager mLayerManager; - - final GLView mGLView; - private final JobQueue mJobQueue; - - // TODO use 1 download and 1 generator thread instead - private final MapWorker mMapWorkers[]; - private final int mNumMapWorkers = 4; - - private MapOptions mMapOptions; - private IMapDatabase mMapDatabase; - private String mRenderTheme; private DebugSettings mDebugSettings; - private boolean mClearMap; - private int mWidth; private int mHeight; // FIXME: keep until old pbmap reader is removed public static boolean enableClosePolygons = false; - public final float dpi; + public static float dpi; /** * @param context @@ -152,21 +117,12 @@ public class MapView extends RelativeLayout { mCompass = new Compass(mapActivity, this); - mJobQueue = new JobQueue(); - - mTileManager = new TileManager(this); - mGLView = new GLView(context, this); - mMapWorkers = new MapWorker[mNumMapWorkers]; mDebugSettings = new DebugSettings(); - TileGenerator.setDebugSettings(mDebugSettings); - for (int i = 0; i < mNumMapWorkers; i++) { - TileGenerator tileGenerator = new TileGenerator(); - mMapWorkers[i] = new MapWorker(i, mJobQueue, tileGenerator, mTileManager); - mMapWorkers[i].start(); - } + // FIXME + TileGenerator.setDebugSettings(mDebugSettings); mapActivity.registerMapView(this); @@ -176,7 +132,19 @@ public class MapView extends RelativeLayout { addView(mGLView, params); - mLayerManager.add(new MapEventLayer(this)); + requestRedraw(); + } + + + public TileLayer setBaseMap(MapOptions options){ + TileLayer baseLayer = new TileLayer(this); + + baseLayer.setMapDatabase(options); + + + mLayerManager.add(0,new MapEventLayer(this)); + + mLayerManager.add(1,baseLayer); //mMapZoomControls = new MapZoomControls(mapActivity, this); //mMapZoomControls.setShowMapZoomControls(true); @@ -184,41 +152,14 @@ public class MapView extends RelativeLayout { //mLayerManager.add(new GenericOverlay(this, new GridOverlay(this))); - mLayerManager.add(new BuildingOverlay(this)); - mLayerManager.add(new LabelingOverlay(this)); + mLayerManager.add(new BuildingOverlay(this, baseLayer.getTileLayer())); + mLayerManager.add(new LabelingOverlay(this, baseLayer.getTileLayer())); - //mLayerManager.add(new GenericOverlay(this, new TileOverlay(this))); - //mLayerManager.add(new GenericOverlay(this, new CustomOverlay(this))); - //mLayerManager.add(new MapLensOverlay(this)); - - //PathOverlay path = new PathOverlay(this, Color.RED); - //path.addGreatCircle(new GeoPoint(53.1, 8.8), new GeoPoint(53.1, -110.0)); - //mLayerManager.add(path); - //path = new PathOverlay(this, Color.GREEN); - //path.addGreatCircle(new GeoPoint(53.1, 140), new GeoPoint(53.1, -110.0)); - //mLayerManager.add(path); - - //mLayerManager.add(new GenericOverlay(this, new AtlasTest(this))); - - clearMap(); + return baseLayer; } void destroy() { - mTileManager.destroy(); - - for (MapWorker mapWorker : mMapWorkers) { - mapWorker.pause(); - mapWorker.interrupt(); - - mapWorker.getTileGenerator().getMapDatabase().close(); - - try { - mapWorker.join(10000); - } catch (InterruptedException e) { - // restore the interrupted status - Thread.currentThread().interrupt(); - } - } + mLayerManager.destroy(); } private boolean mPausing = false; @@ -226,18 +167,12 @@ public class MapView extends RelativeLayout { void onPause() { mPausing = true; - Log.d(TAG, "onPause"); - mJobQueue.clear(); - mapWorkersPause(true); - if (this.mCompassEnabled) mCompass.disable(); } void onResume() { - Log.d(TAG, "onResume"); - mapWorkersProceed(); if (this.mCompassEnabled) mCompass.enable(); @@ -247,7 +182,7 @@ public class MapView extends RelativeLayout { public void onStop() { Log.d(TAG, "onStop"); - //mTileManager.destroy(); + //mLayerManager.destroy(); } @Override @@ -264,9 +199,6 @@ public class MapView extends RelativeLayout { int oldWidth, int oldHeight) { Log.d(TAG, "onSizeChanged: " + width + "x" + height); - mJobQueue.clear(); - mapWorkersPause(true); - super.onSizeChanged(width, height, oldWidth, oldHeight); mWidth = width; @@ -274,9 +206,6 @@ public class MapView extends RelativeLayout { if (width != 0 && height != 0) mMapViewPosition.setViewport(width, height); - - clearMap(); - mapWorkersProceed(); } public void render() { @@ -315,6 +244,24 @@ public class MapView extends RelativeLayout { return mRotationEnabled; } + + boolean mWaitRedraw; + + Runnable mRedrawRequest = new Runnable() { + @Override + public void run() { + mWaitRedraw = false; + redrawMap(true); + } + }; + + public void requestRedraw(){ + if (!mWaitRedraw){ + mWaitRedraw = true; + post(mRedrawRequest); + } + } + /** * Calculates all necessary tiles and adds jobs accordingly. * @@ -324,33 +271,27 @@ public class MapView extends RelativeLayout { if (mPausing || mWidth == 0 || mHeight == 0) return; - if (forceRedraw) + boolean changed = false; + + if (forceRedraw){ render(); - - if (mClearMap) { - mTileManager.init(mWidth, mHeight); - mClearMap = false; - - // make sure mMapPosition will be updated - mMapPosition.zoomLevel = -1; - - // TODO clear overlays + changed = true; } +// if (mClearMap) { +// mTileManager.init(mWidth, mHeight); +// mClearMap = false; +// +// // make sure mMapPosition will be updated +// mMapPosition.zoomLevel = -1; +// +// // TODO clear overlays +// } - boolean changed = mMapViewPosition.getMapPosition(mMapPosition); + changed |= mMapViewPosition.getMapPosition(mMapPosition); // required when not changed? if (AndroidUtils.currentThreadIsUiThread()) mLayerManager.onUpdate(mMapPosition, changed); - - if (changed) { - mTileManager.update(mMapPosition); - } - } - - private void clearMap() { - // clear tile and overlay data before next draw - mClearMap = true; } /** @@ -360,7 +301,7 @@ public class MapView extends RelativeLayout { public void setDebugSettings(DebugSettings debugSettings) { mDebugSettings = debugSettings; TileGenerator.setDebugSettings(debugSettings); - clearMap(); + //clearMap(); } /** @@ -370,184 +311,10 @@ public class MapView extends RelativeLayout { return mDebugSettings; } - public Map getMapOptions() { - return mMapOptions; - } - - public MapPosition getMapFileCenter() { - if (mMapDatabase == null) - return null; - - MapInfo mapInfo = mMapDatabase.getMapInfo(); - if (mapInfo == null) - return null; - - GeoPoint startPos = mapInfo.startPosition; - - if (startPos == null) - startPos = mapInfo.mapCenter; - - if (startPos == null) - startPos = new GeoPoint(0, 0); - - MapPosition mapPosition = new MapPosition(); - mapPosition.setPosition(startPos); - - if (mapInfo.startZoomLevel == null) - mapPosition.setZoomLevel(12); - else - mapPosition.setZoomLevel((mapInfo.startZoomLevel).byteValue()); - - return mapPosition; - } - public void setMapPosition(MapPosition mapPosition) { mMapViewPosition.setMapPosition(mapPosition); } - /** - * Sets the MapDatabase for this MapView. - * - * @param options - * the new MapDatabase options. - * @return true if MapDatabase changed - */ - public boolean setMapDatabase(MapOptions options) { - if (debugDatabase) - return false; - - Log.i(TAG, "setMapDatabase: " + options.db.name()); - - if (mMapOptions != null && mMapOptions.equals(options)) - return true; - - mapWorkersPause(true); - - mJobQueue.clear(); - mMapOptions = options; - - mMapDatabase = null; - - for (int i = 0; i < mNumMapWorkers; i++) { - MapWorker mapWorker = mMapWorkers[i]; - - IMapDatabase mapDatabase = MapDatabaseFactory - .createMapDatabase(options.db); - - OpenResult result = mapDatabase.open(options); - - if (result != OpenResult.SUCCESS) { - Log.d(TAG, "failed open db: " + result.getErrorMessage()); - } - - TileGenerator tileGenerator = mapWorker.getTileGenerator(); - tileGenerator.setMapDatabase(mapDatabase); - - // TODO this could be done in a cleaner way.. - if (mMapDatabase == null) - mMapDatabase = mapDatabase; - } - - if (options.db == MapDatabases.OSCIMAP_READER || - options.db == MapDatabases.MAP_READER) - MapView.enableClosePolygons = true; - else - MapView.enableClosePolygons = false; - - clearMap(); - - mapWorkersProceed(); - - return true; - } - - public String getRenderTheme() { - return mRenderTheme; - } - - /** - * Sets the internal theme which is used for rendering the map. - * - * @param internalRenderTheme - * the internal rendering theme. - * @return ... - * @throws IllegalArgumentException - * if the supplied internalRenderTheme is null. - */ - public boolean setRenderTheme(InternalRenderTheme internalRenderTheme) { - if (internalRenderTheme == null) { - throw new IllegalArgumentException("render theme must not be null"); - } - - if (internalRenderTheme.name() == mRenderTheme) - return true; - - boolean ret = setRenderTheme((Theme) internalRenderTheme); - if (ret) { - mRenderTheme = internalRenderTheme.name(); - } - - clearMap(); - - return ret; - } - - /** - * Sets the theme file which is used for rendering the map. - * - * @param renderThemePath - * the path to the XML file which defines the rendering theme. - * @throws IllegalArgumentException - * if the supplied internalRenderTheme is null. - * @throws FileNotFoundException - * if the supplied file does not exist, is a directory or cannot - * be read. - */ - public void setRenderTheme(String renderThemePath) throws FileNotFoundException { - if (renderThemePath == null) { - throw new IllegalArgumentException("render theme path must not be null"); - } - - boolean ret = setRenderTheme(new ExternalRenderTheme(renderThemePath)); - if (ret) { - mRenderTheme = renderThemePath; - } - - clearMap(); - } - - private boolean setRenderTheme(Theme theme) { - - mapWorkersPause(true); - - InputStream inputStream = null; - try { - inputStream = theme.getRenderThemeAsStream(); - RenderTheme t = RenderThemeHandler.getRenderTheme(inputStream); - t.scaleTextSize(1 + (dpi / 240 - 1) * 0.5f); - // FIXME - GLRenderer.setRenderTheme(t); - TileGenerator.setRenderTheme(t); - return true; - } catch (ParserConfigurationException e) { - Log.e(TAG, e.getMessage()); - } catch (SAXException e) { - Log.e(TAG, e.getMessage()); - } catch (IOException e) { - Log.e(TAG, e.getMessage()); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - } catch (IOException e) { - Log.e(TAG, e.getMessage()); - } - mapWorkersProceed(); - } - return false; - } - /** * Sets the center of the MapView and triggers a redraw. * @@ -567,45 +334,6 @@ public class MapView extends RelativeLayout { return mMapViewPosition; } - /** - * add jobs and remember MapWorkers that stuff needs to be done - * - * @param jobs - * tile jobs - */ - public void addJobs(JobTile[] jobs) { - if (jobs == null) { - mJobQueue.clear(); - return; - } - mJobQueue.setJobs(jobs); - - for (int i = 0; i < mNumMapWorkers; i++) { - MapWorker m = mMapWorkers[i]; - synchronized (m) { - m.notify(); - } - } - } - - private void mapWorkersPause(boolean wait) { - for (MapWorker mapWorker : mMapWorkers) { - if (!mapWorker.isPausing()) - mapWorker.pause(); - } - if (wait) { - for (MapWorker mapWorker : mMapWorkers) { - if (!mapWorker.isPausing()) - mapWorker.awaitPausing(); - } - } - } - - private void mapWorkersProceed() { - for (MapWorker mapWorker : mMapWorkers) - mapWorker.proceed(); - } - /** * You can add/remove/reorder your Overlays using the List of * {@link Overlay}. The first (index 0) Overlay gets drawn first, the one @@ -613,7 +341,7 @@ public class MapView extends RelativeLayout { * * @return ... */ - public List getOverlays() { + public List getOverlays() { return this.getOverlayManager(); } @@ -621,10 +349,6 @@ public class MapView extends RelativeLayout { return mLayerManager; } - public TileManager getTileManager() { - return mTileManager; - } - /** * @return estimated visible axis aligned bounding box */