diff --git a/src/org/oscim/layers/tile/BitmapTileLayer.java b/src/org/oscim/layers/tile/BitmapTileLayer.java new file mode 100644 index 00000000..0f3d101d --- /dev/null +++ b/src/org/oscim/layers/tile/BitmapTileLayer.java @@ -0,0 +1,87 @@ +/* + * 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.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.zip.GZIPInputStream; + +import org.oscim.layers.tile.bitmap.TileSource; +import org.oscim.renderer.layer.BitmapLayer; +import org.oscim.renderer.layer.Layers; +import org.oscim.view.MapView; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + +public class BitmapTileLayer extends TileLayer { + private static final int TIMEOUT_CONNECT = 5000; + private static final int TIMEOUT_READ = 10000; + + final TileSource mTileSource; + + public BitmapTileLayer(MapView mapView, TileSource tileSource) { + super(mapView); + mTileSource = tileSource; + } + + @Override + protected TileLoader createLoader(JobQueue q, TileManager tm) { + return new TileLoader(q, tm) { + + @Override + protected boolean executeJob(MapTile tile) { + URL url; + try { + url = mTileSource.getTileUrl(tile); + URLConnection urlConnection = getURLConnection(url); + InputStream inputStream = getInputStream(urlConnection); + Bitmap bitmap = BitmapFactory.decodeStream(inputStream); + + tile.layers = new Layers(); + BitmapLayer l = new BitmapLayer(); + l.setBitmap(bitmap); + + tile.layers.textureLayers = l; + + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return false; + } + + @Override + public void cleanup() { + } + + private InputStream getInputStream(URLConnection urlConnection) throws IOException { + if ("gzip".equals(urlConnection.getContentEncoding())) { + return new GZIPInputStream(urlConnection.getInputStream()); + } + return urlConnection.getInputStream(); + } + + private URLConnection getURLConnection(URL url) throws IOException { + URLConnection urlConnection = url.openConnection(); + urlConnection.setConnectTimeout(TIMEOUT_CONNECT); + urlConnection.setReadTimeout(TIMEOUT_READ); + return urlConnection; + } + }; + } +} diff --git a/src/org/oscim/layers/tile/TileLoader.java b/src/org/oscim/layers/tile/TileLoader.java index 667df3da..c8e5f4f3 100644 --- a/src/org/oscim/layers/tile/TileLoader.java +++ b/src/org/oscim/layers/tile/TileLoader.java @@ -19,9 +19,6 @@ import org.oscim.utils.PausableThread; public abstract class TileLoader extends PausableThread { private static int id; - public interface Factory{ - T create(JobQueue jobQueue, TileManager tileManager); - } private final String THREAD_NAME; private final JobQueue mJobQueue; diff --git a/src/org/oscim/layers/tile/TileRenderer.java b/src/org/oscim/layers/tile/TileRenderer.java index df0d1dc3..477da6dc 100644 --- a/src/org/oscim/layers/tile/TileRenderer.java +++ b/src/org/oscim/layers/tile/TileRenderer.java @@ -22,6 +22,7 @@ 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.layer.BitmapRenderer; import org.oscim.renderer.layer.Layer; import org.oscim.renderer.layer.LineRenderer; import org.oscim.renderer.layer.LineTexRenderer; @@ -185,6 +186,17 @@ public class TileRenderer { } } + for (Layer l = t.layers.textureLayers; l != null;) { + switch (l.type) { + case Layer.BITMAP: + l = BitmapRenderer.draw(l, 1, m); + break; + + default: + l = l.next; + } + } + // clear clip-region and could also draw 'fade-effect' if (mFaded) PolygonRenderer.drawOver(m, true, 0x22000000); diff --git a/src/org/oscim/layers/tile/bitmap/AbstractTileSource.java b/src/org/oscim/layers/tile/bitmap/AbstractTileSource.java new file mode 100644 index 00000000..ce96a37f --- /dev/null +++ b/src/org/oscim/layers/tile/bitmap/AbstractTileSource.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010, 2011, 2012 mapsforge.org + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . + */ +package org.oscim.layers.tile.bitmap; + +public abstract class AbstractTileSource implements TileSource { + protected final String hostName; + protected final int port; + + protected AbstractTileSource(String hostName, int port) { + if (hostName == null || hostName.isEmpty()) { + throw new IllegalArgumentException("no host name specified"); + } else if (port < 0 || port > 65535) { + throw new IllegalArgumentException("invalid port number: " + port); + } + + this.hostName = hostName; + this.port = port; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (!(obj instanceof AbstractTileSource)) { + return false; + } + AbstractTileSource other = (AbstractTileSource) obj; + if (!this.hostName.equals(other.hostName)) { + return false; + } else if (this.port != other.port) { + return false; + } + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + this.hostName.hashCode(); + result = prime * result + this.port; + return result; + } +} diff --git a/src/org/oscim/layers/tile/bitmap/MapQuestAerial.java b/src/org/oscim/layers/tile/bitmap/MapQuestAerial.java new file mode 100644 index 00000000..78d99ab7 --- /dev/null +++ b/src/org/oscim/layers/tile/bitmap/MapQuestAerial.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010, 2011, 2012 mapsforge.org + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . + */ +package org.oscim.layers.tile.bitmap; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.oscim.core.Tile; + +public class MapQuestAerial extends AbstractTileSource { + public static final MapQuestAerial INSTANCE = new MapQuestAerial("otile1.mqcdn.com", 80); + private static final int PARALLEL_REQUESTS_LIMIT = 8; + private static final String PROTOCOL = "http"; + private static final int ZOOM_LEVEL_MAX = 18; + private static final int ZOOM_LEVEL_MIN = 0; + + public MapQuestAerial(String hostName, int port) { + super(hostName, port); + } + + @Override + public int getParallelRequestsLimit() { + return PARALLEL_REQUESTS_LIMIT; + } + + @Override + public URL getTileUrl(Tile tile) throws MalformedURLException { + StringBuilder stringBuilder = new StringBuilder(32); + + stringBuilder.append("/tiles/1.0.0/sat/"); + stringBuilder.append(tile.zoomLevel); + stringBuilder.append('/'); + stringBuilder.append(tile.tileX); + stringBuilder.append('/'); + stringBuilder.append(tile.tileY); + stringBuilder.append(".jpg"); + + return new URL(PROTOCOL, this.hostName, this.port, stringBuilder.toString()); + } + + @Override + public byte getZoomLevelMax() { + return ZOOM_LEVEL_MAX; + } + + @Override + public byte getZoomLevelMin() { + return ZOOM_LEVEL_MIN; + } +} diff --git a/src/org/oscim/layers/tile/bitmap/OpenStreetMapMapnik.java b/src/org/oscim/layers/tile/bitmap/OpenStreetMapMapnik.java new file mode 100644 index 00000000..0357d36b --- /dev/null +++ b/src/org/oscim/layers/tile/bitmap/OpenStreetMapMapnik.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010, 2011, 2012 mapsforge.org + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . + */ +package org.oscim.layers.tile.bitmap; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.oscim.core.Tile; + +public class OpenStreetMapMapnik extends AbstractTileSource { + public static final OpenStreetMapMapnik INSTANCE = new OpenStreetMapMapnik("tile.openstreetmap.org", 80); + private static final int PARALLEL_REQUESTS_LIMIT = 8; + private static final String PROTOCOL = "http"; + private static final int ZOOM_LEVEL_MAX = 18; + private static final int ZOOM_LEVEL_MIN = 0; + + public OpenStreetMapMapnik(String hostName, int port) { + super(hostName, port); + } + + @Override + public int getParallelRequestsLimit() { + return PARALLEL_REQUESTS_LIMIT; + } + + @Override + public URL getTileUrl(Tile tile) throws MalformedURLException { + StringBuilder stringBuilder = new StringBuilder(32); + + stringBuilder.append('/'); + stringBuilder.append(tile.zoomLevel); + stringBuilder.append('/'); + stringBuilder.append(tile.tileX); + stringBuilder.append('/'); + stringBuilder.append(tile.tileY); + stringBuilder.append(".png"); + + return new URL(PROTOCOL, this.hostName, this.port, stringBuilder.toString()); + } + + @Override + public byte getZoomLevelMax() { + return ZOOM_LEVEL_MAX; + } + + @Override + public byte getZoomLevelMin() { + return ZOOM_LEVEL_MIN; + } +} diff --git a/src/org/oscim/layers/tile/bitmap/TileSource.java b/src/org/oscim/layers/tile/bitmap/TileSource.java new file mode 100644 index 00000000..00baa085 --- /dev/null +++ b/src/org/oscim/layers/tile/bitmap/TileSource.java @@ -0,0 +1,42 @@ +/* + * Copyright 2010, 2011, 2012 mapsforge.org + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . + */ +package org.oscim.layers.tile.bitmap; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.oscim.core.Tile; + +public interface TileSource { + /** + * @return the maximum number of parallel requests which this {@code TileSource} supports. + */ + int getParallelRequestsLimit(); + + /** + * @return the download URL for the given {@code Tile}. + */ + URL getTileUrl(Tile tile) throws MalformedURLException; + + /** + * @return the maximum zoom level which this {@code TileSource} supports. + */ + byte getZoomLevelMax(); + + /** + * @return the minimum zoom level which this {@code TileSource} supports. + */ + byte getZoomLevelMin(); +} diff --git a/src/org/oscim/renderer/GLRenderer.java b/src/org/oscim/renderer/GLRenderer.java index 2e5ee532..fad51c04 100644 --- a/src/org/oscim/renderer/GLRenderer.java +++ b/src/org/oscim/renderer/GLRenderer.java @@ -243,8 +243,8 @@ public class GLRenderer implements GLSurfaceView.Renderer { | GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT); - boolean tilesChanged = true; - boolean positionChanged = true; + boolean tilesChanged = false; + boolean positionChanged = false; // get current MapPosition, set mBoxCoords (mapping of screen to model // coordinates) @@ -253,7 +253,7 @@ public class GLRenderer implements GLSurfaceView.Renderer { synchronized (mMapViewPosition) { mMapViewPosition.updateAnimation(); - positionChanged |= mMapViewPosition.getMapPosition(pos); + positionChanged = mMapViewPosition.getMapPosition(pos); if (positionChanged) mMapViewPosition.getMapViewProjection(mBoxCoords); diff --git a/src/org/oscim/renderer/layer/BitmapLayer.java b/src/org/oscim/renderer/layer/BitmapLayer.java new file mode 100644 index 00000000..023c822b --- /dev/null +++ b/src/org/oscim/renderer/layer/BitmapLayer.java @@ -0,0 +1,117 @@ +/* + * 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.renderer.layer; + +import java.nio.ShortBuffer; + +import org.oscim.core.Tile; +import org.oscim.renderer.GLRenderer; + +import android.graphics.Bitmap; + +public class BitmapLayer extends TextureLayer { + // private final static String TAG = BitmapLayer.class.getName(); + private Bitmap mBitmap; + + public BitmapLayer() { + type = Layer.BITMAP; + } + + public void setBitmap(Bitmap bitmap) { + mBitmap = bitmap; + + vertexItems = VertexItem.pool.get(); + short[] buf = vertexItems.vertices; + short size = (short) (Tile.SIZE * GLRenderer.COORD_SCALE); + short center = (short) (size >> 1); + short m = (short) (-(size >> 1)); + short p = center; + short t = (8 * 256); + + int pos = 0; + // top-left + buf[pos++] = 0; + buf[pos++] = 0; + buf[pos++] = m; + buf[pos++] = m; + buf[pos++] = 0; + buf[pos++] = 0; + // bot-left + buf[pos++] = 0; + buf[pos++] = size; + buf[pos++] = m; + buf[pos++] = p; + buf[pos++] = 0; + buf[pos++] = t; + // top-right + buf[pos++] = size; + buf[pos++] = 0; + buf[pos++] = p; + buf[pos++] = m; + buf[pos++] = t; + buf[pos++] = 0; + // bot-right + buf[pos++] = size; + buf[pos++] = size; + buf[pos++] = p; + buf[pos++] = p; + buf[pos++] = t; + buf[pos++] = t; + + vertexItems.used = 24; + + TextureItem ti = this.textures = new TextureItem(-1); + ti.ownBitmap = true; + ti.width = mBitmap.getWidth(); + ti.height = mBitmap.getHeight(); + ti.bitmap = mBitmap; + ti.vertices = TextureRenderer.INDICES_PER_SPRITE; + + verticesCnt = 4; + } + + @Override + public boolean prepare() { + return false; + } + + @Override + protected void compile(ShortBuffer sbuf) { + if (mBitmap == null) + return; + + super.compile(sbuf); + + mBitmap.recycle(); + mBitmap = null; + textures.bitmap = null; + } + + @Override + protected void clear() { + + if (mBitmap != null) { + mBitmap.recycle(); + mBitmap = null; + textures.bitmap = null; + } + + TextureItem.releaseTexture(textures); + textures = null; + + VertexItem.pool.releaseAll(vertexItems); + vertexItems = null; + } +} diff --git a/src/org/oscim/renderer/layer/BitmapRenderer.java b/src/org/oscim/renderer/layer/BitmapRenderer.java new file mode 100644 index 00000000..2d30cd2f --- /dev/null +++ b/src/org/oscim/renderer/layer/BitmapRenderer.java @@ -0,0 +1,141 @@ +/* + * Copyright 2012, 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.renderer.layer; + +import static org.oscim.renderer.GLRenderer.COORD_SCALE; +import static org.oscim.renderer.layer.TextureItem.TEXTURE_HEIGHT; + +import org.oscim.renderer.GLRenderer; +import org.oscim.renderer.GLRenderer.Matrices; +import org.oscim.renderer.GLState; +import org.oscim.utils.GlUtils; + +import android.opengl.GLES20; + +/** + * @author Hannes Janetzek + */ +public final class BitmapRenderer { + private final static String TAG = BitmapRenderer.class.getName(); + public final static boolean debug = true; + + private static int mTextureProgram; + private static int hTextureMVMatrix; + private static int hTextureProjMatrix; + private static int hTextureVertex; + private static int hTextureScale; + private static int hTextureScreenScale; + private static int hTextureTexCoord; + + public final static int INDICES_PER_SPRITE = 6; + final static int VERTICES_PER_SPRITE = 4; + final static int SHORTS_PER_VERTICE = 6; + + static void init() { + mTextureProgram = GlUtils.createProgram(textVertexShader, + textFragmentShader); + + hTextureMVMatrix = GLES20.glGetUniformLocation(mTextureProgram, "u_mv"); + hTextureProjMatrix = GLES20.glGetUniformLocation(mTextureProgram, "u_proj"); + hTextureScale = GLES20.glGetUniformLocation(mTextureProgram, "u_scale"); + hTextureScreenScale = GLES20.glGetUniformLocation(mTextureProgram, "u_swidth"); + hTextureVertex = GLES20.glGetAttribLocation(mTextureProgram, "vertex"); + hTextureTexCoord = GLES20.glGetAttribLocation(mTextureProgram, "tex_coord"); + } + + public static Layer draw(Layer layer, float scale, Matrices m) { + GLState.test(false, false); + GLState.blend(true); + + GLState.useProgram(mTextureProgram); + + GLState.enableVertexArrays(hTextureTexCoord, hTextureVertex); + + TextureLayer tl = (TextureLayer) layer; + + if (tl.fixed) + GLES20.glUniform1f(hTextureScale, (float) Math.sqrt(scale)); + else + GLES20.glUniform1f(hTextureScale, 1); + + GLES20.glUniform1f(hTextureScreenScale, 1f / GLRenderer.screenWidth); + + m.proj.setAsUniform(hTextureProjMatrix); + + m.mvp.setAsUniform(hTextureMVMatrix); + + GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, GLRenderer.mQuadIndicesID); + + for (TextureItem ti = tl.textures; ti != null; ti = ti.next) { + //Log.d(TAG, "render texture " + ti.id); + + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, ti.id); + int maxVertices = GLRenderer.maxQuads * INDICES_PER_SPRITE; + + // draw up to maxVertices in each iteration + for (int i = 0; i < ti.vertices; i += maxVertices) { + // to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8) + int off = (ti.offset + i) * 8 + tl.offset; + + GLES20.glVertexAttribPointer(hTextureVertex, 4, + GLES20.GL_SHORT, false, 12, off); + + GLES20.glVertexAttribPointer(hTextureTexCoord, 2, + GLES20.GL_SHORT, false, 12, off + 8); + + int numVertices = ti.vertices - i; + if (numVertices > maxVertices) + numVertices = maxVertices; + + GLES20.glDrawElements(GLES20.GL_TRIANGLES, numVertices, + GLES20.GL_UNSIGNED_SHORT, 0); + } + } + + GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0); + + return layer.next; + } + + //private final static double TEX_COORD_DIV_X = 1.0 / (TEXTURE_WIDTH * COORD_SCALE); + private final static double TEX_COORD_DIV_X = 1.0 / (TEXTURE_HEIGHT* COORD_SCALE); + private final static double TEX_COORD_DIV_Y = 1.0 / (TEXTURE_HEIGHT * COORD_SCALE); + private final static double COORD_DIV = 1.0 / GLRenderer.COORD_SCALE; + + private final static String textVertexShader = "" + + "precision mediump float; " + + "attribute vec4 vertex;" + + "attribute vec2 tex_coord;" + + "uniform mat4 u_mv;" + + "uniform mat4 u_proj;" + + "uniform float u_scale;" + + "uniform float u_swidth;" + + "varying vec2 tex_c;" + + "const vec2 div = vec2(" + TEX_COORD_DIV_X + "," + TEX_COORD_DIV_Y + ");" + + "const float coord_scale = " + COORD_DIV + ";" + + "void main() {" + + " gl_Position = u_mv * vec4(vertex.xy, 0.0, 1.0);" + + " tex_c = tex_coord * div;" + + "}"; + + private final static String textFragmentShader = "" + + "precision mediump float;" + + "uniform sampler2D tex;" + + "varying vec2 tex_c;" + + "void main() {" + + " gl_FragColor = texture2D(tex, tex_c.xy);" + + "}"; +} diff --git a/src/org/oscim/renderer/layer/Layers.java b/src/org/oscim/renderer/layer/Layers.java index 3d032992..65f359ac 100644 --- a/src/org/oscim/renderer/layer/Layers.java +++ b/src/org/oscim/renderer/layer/Layers.java @@ -28,6 +28,7 @@ public class Layers { LineTexRenderer.init(); PolygonRenderer.init(); TextureRenderer.init(); + BitmapRenderer.init(); TextureItem.init(10); } diff --git a/src/org/oscim/renderer/layer/SymbolLayer.java b/src/org/oscim/renderer/layer/SymbolLayer.java index 99fe2b03..668117cf 100644 --- a/src/org/oscim/renderer/layer/SymbolLayer.java +++ b/src/org/oscim/renderer/layer/SymbolLayer.java @@ -102,7 +102,7 @@ public final class SymbolLayer extends TextureLayer { float x = 0; float y = 0; - TextureItem to = TextureItem.pool.get(); + TextureItem to = TextureItem.get(true); textures = to; mCanvas.setBitmap(to.bitmap); @@ -138,7 +138,7 @@ public final class SymbolLayer extends TextureLayer { offsetIndices = numIndices; curIndices = 0; - to.next = TextureItem.pool.get(); + to.next = TextureItem.get(true); to = to.next; mCanvas.setBitmap(to.bitmap); @@ -247,7 +247,8 @@ public final class SymbolLayer extends TextureLayer { @Override protected void clear() { - TextureItem.pool.releaseAll(textures); + TextureItem.releaseAll(textures); + SymbolItem.pool.releaseAll(symbols); VertexItem.pool.releaseAll(vertexItems); textures = null; diff --git a/src/org/oscim/renderer/layer/TextLayer.java b/src/org/oscim/renderer/layer/TextLayer.java index cb6a1e4c..5da2f7ac 100644 --- a/src/org/oscim/renderer/layer/TextLayer.java +++ b/src/org/oscim/renderer/layer/TextLayer.java @@ -17,8 +17,6 @@ package org.oscim.renderer.layer; import static org.oscim.renderer.GLRenderer.COORD_SCALE; import static org.oscim.renderer.layer.TextureItem.TEXTURE_HEIGHT; import static org.oscim.renderer.layer.TextureItem.TEXTURE_WIDTH; - - import android.graphics.Canvas; public final class TextLayer extends TextureLayer { @@ -91,7 +89,7 @@ public final class TextLayer extends TextureLayer { float y = 0; float yy; - TextureItem to = TextureItem.pool.get(); + TextureItem to = TextureItem.get(true); textures = to; mCanvas.setBitmap(to.bitmap); @@ -113,7 +111,7 @@ public final class TextLayer extends TextureLayer { to.vertices = (short) (numIndices - offsetIndices); offsetIndices = numIndices; - to.next = TextureItem.pool.get(); + to.next = TextureItem.get(true); to = to.next; mCanvas.setBitmap(to.bitmap); @@ -266,7 +264,7 @@ public final class TextLayer extends TextureLayer { @Override protected void clear() { - TextureItem.pool.releaseAll(textures); + TextureItem.releaseAll(textures); TextItem.pool.releaseAll(labels); VertexItem.pool.releaseAll(vertexItems); textures = null; diff --git a/src/org/oscim/renderer/layer/TextureItem.java b/src/org/oscim/renderer/layer/TextureItem.java index 4a9bff02..6372b74b 100644 --- a/src/org/oscim/renderer/layer/TextureItem.java +++ b/src/org/oscim/renderer/layer/TextureItem.java @@ -16,6 +16,7 @@ package org.oscim.renderer.layer; import java.util.ArrayList; +import org.oscim.utils.GlUtils; import org.oscim.utils.pool.Inlist; import org.oscim.utils.pool.SyncPool; @@ -44,15 +45,30 @@ public class TextureItem extends Inlist { // temporary Bitmap public Bitmap bitmap; + boolean ownBitmap; + TextureItem(int id) { this.id = id; } - public final static SyncPool pool = new SyncPool() { + public synchronized static void releaseAll(TextureItem ti) { + pool.releaseAll(ti); + } + + public synchronized static TextureItem get(boolean initBitmap) { + TextureItem ti = pool.get(); + if (initBitmap) { + ti.bitmap = getBitmap(); + ti.bitmap.eraseColor(Color.TRANSPARENT); + } + return ti; + } + + private final static SyncPool pool = new SyncPool(20) { @Override public void init(int num) { - this.pool = null; + super.init(num); int[] textureIds = new int[num]; GLES20.glGenTextures(num, textureIds, 0); @@ -60,22 +76,10 @@ public class TextureItem extends Inlist { for (int i = 1; i < num; i++) { initTexture(textureIds[i]); TextureItem to = new TextureItem(textureIds[i]); - - to.next = this.pool; - this.pool = to; + pool = Inlist.push(pool, to); } } - @Override - public TextureItem get() { - TextureItem it = super.get(); - - it.bitmap = TextureItem.getBitmap(); - it.bitmap.eraseColor(Color.TRANSPARENT); - - return it; - } - @Override protected TextureItem createItem() { return new TextureItem(-1); @@ -83,10 +87,22 @@ public class TextureItem extends Inlist { @Override protected void clearItem(TextureItem it) { - TextureItem.releaseBitmap(it); + //Log.d(TAG, it.ownBitmap + " " + (it.bitmap == null)); + if (it.ownBitmap) + return; + + releaseBitmap(it); + } + + @Override + protected void freeItem(TextureItem it) { + it.width = -1; + it.height = -1; + releaseTexture(it); } }; + private static ArrayList mFreeTextures = new ArrayList(); private static ArrayList mBitmaps = new ArrayList(10); public final static int TEXTURE_WIDTH = 512; @@ -94,6 +110,27 @@ public class TextureItem extends Inlist { private static int mBitmapFormat; private static int mBitmapType; + private static int mTexCnt = 0; + + static void releaseTexture(TextureItem it) { + synchronized (mFreeTextures) { + if (it.id >= 0) { + mFreeTextures.add(Integer.valueOf(it.id)); + it.id = -1; + } + } + } + + static void releaseBitmap(TextureItem it) { + synchronized (mBitmaps) { + if (it.bitmap != null) { + mBitmaps.add(it.bitmap); + it.bitmap = null; + } + it.ownBitmap = false; + + } + } /** * This function may only be used in GLRenderer Thread. @@ -102,23 +139,32 @@ public class TextureItem extends Inlist { */ public static void uploadTexture(TextureItem to) { - if (TextureRenderer.debug) - Log.d(TAG, "upload texture " + to.id); + // free unused textures, find a better place for this TODO + synchronized (mFreeTextures) { + int size = mFreeTextures.size(); + int[] tmp = new int[size]; + for (int i = 0; i < size; i++) + tmp[i] = mFreeTextures.get(i).intValue(); + mFreeTextures.clear(); + GLES20.glDeleteTextures(size, tmp, 0); + } if (to.id < 0) { + mTexCnt++; int[] textureIds = new int[1]; GLES20.glGenTextures(1, textureIds, 0); to.id = textureIds[0]; initTexture(to.id); - if (TextureRenderer.debug) - Log.d(TAG, "new texture " + to.id); + Log.d(TAG, pool.getCount() + " " + pool.getFill() + + " " + mTexCnt + " new texture " + to.id); } uploadTexture(to, to.bitmap, mBitmapFormat, mBitmapType, TEXTURE_WIDTH, TEXTURE_HEIGHT); - TextureItem.releaseBitmap(to); + if (!to.ownBitmap) + TextureItem.releaseBitmap(to); } public static void uploadTexture(TextureItem to, Bitmap bitmap, @@ -129,13 +175,21 @@ public class TextureItem extends Inlist { return; } GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, to.id); - if (to.width == w && to.height == h) + + if (to.ownBitmap) { + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); + + } else if (to.width == w && to.height == h) { GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, bitmap, format, type); - else { + + } else { GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, format, bitmap, type, 0); to.width = w; to.height = h; } + + if (TextureRenderer.debug) + GlUtils.checkGlError(TAG); } static void initTexture(int id) { @@ -166,6 +220,8 @@ public class TextureItem extends Inlist { mBitmapFormat = GLUtils.getInternalFormat(mBitmaps.get(0)); mBitmapType = GLUtils.getType(mBitmaps.get(0)); + + mTexCnt = num; } static Bitmap getBitmap() { @@ -186,14 +242,4 @@ public class TextureItem extends Inlist { return mBitmaps.remove(size - 1); } } - - static void releaseBitmap(TextureItem it) { - synchronized (mBitmaps) { - - if (it.bitmap != null) { - mBitmaps.add(it.bitmap); - it.bitmap = null; - } - } - } } diff --git a/src/org/oscim/renderer/layer/TextureRenderer.java b/src/org/oscim/renderer/layer/TextureRenderer.java index 520a3530..c368d796 100644 --- a/src/org/oscim/renderer/layer/TextureRenderer.java +++ b/src/org/oscim/renderer/layer/TextureRenderer.java @@ -20,8 +20,8 @@ import static org.oscim.renderer.layer.TextureItem.TEXTURE_HEIGHT; import static org.oscim.renderer.layer.TextureItem.TEXTURE_WIDTH; import org.oscim.renderer.GLRenderer; -import org.oscim.renderer.GLState; import org.oscim.renderer.GLRenderer.Matrices; +import org.oscim.renderer.GLState; import org.oscim.utils.GlUtils; import android.opengl.GLES20; @@ -30,6 +30,7 @@ import android.opengl.GLES20; * @author Hannes Janetzek */ public final class TextureRenderer { + //private final static String TAG = TextureRenderer.class.getName(); public final static boolean debug = false; private static int mTextureProgram; @@ -78,15 +79,15 @@ public final class TextureRenderer { GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, GLRenderer.mQuadIndicesID); - for (TextureItem to = tl.textures; to != null; to = to.next) { + for (TextureItem ti = tl.textures; ti != null; ti = ti.next) { - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, to.id); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, ti.id); int maxVertices = GLRenderer.maxQuads * INDICES_PER_SPRITE; // draw up to maxVertices in each iteration - for (int i = 0; i < to.vertices; i += maxVertices) { + for (int i = 0; i < ti.vertices; i += maxVertices) { // to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8) - int off = (to.offset + i) * 8 + tl.offset; + int off = (ti.offset + i) * 8 + tl.offset; GLES20.glVertexAttribPointer(hTextureVertex, 4, GLES20.GL_SHORT, false, 12, off); @@ -94,7 +95,7 @@ public final class TextureRenderer { GLES20.glVertexAttribPointer(hTextureTexCoord, 2, GLES20.GL_SHORT, false, 12, off + 8); - int numVertices = to.vertices - i; + int numVertices = ti.vertices - i; if (numVertices > maxVertices) numVertices = maxVertices; diff --git a/src/org/oscim/renderer/overlays/TextOverlay.java b/src/org/oscim/renderer/overlays/TextOverlay.java index f2566c1c..158bde2c 100644 --- a/src/org/oscim/renderer/overlays/TextOverlay.java +++ b/src/org/oscim/renderer/overlays/TextOverlay.java @@ -33,7 +33,6 @@ import org.oscim.core.Tile; import org.oscim.graphics.Color; import org.oscim.graphics.Paint.Cap; import org.oscim.layers.tile.MapTile; -import org.oscim.layers.tile.MapTile; import org.oscim.layers.tile.TileRenderLayer; import org.oscim.layers.tile.TileSet; import org.oscim.renderer.BufferObject; @@ -61,7 +60,7 @@ import android.opengl.GLES20; import android.os.SystemClock; public class TextOverlay extends BasicOverlay { - //private final static String TAG = TextOverlay.class.getName(); +private final static String TAG = TextOverlay.class.getName(); private final static float MIN_CAPTION_DIST = 5; private final static float MIN_WAY_DIST = 3; @@ -179,7 +178,7 @@ public class TextOverlay extends BasicOverlay { mRun = false; if (updateLabels()) { - mMapView.redrawMap(true); + mMapView.render(); } else { mRun = true; } @@ -695,14 +694,15 @@ public class TextOverlay extends BasicOverlay { // set new TextLayer to be uploaded and rendered layers.textureLayers = mNextLayer; + mNextLayer = null; // make the 'labeled' MapPosition current MapPosition tmp = mMapPosition; mMapPosition = mTmpPos; mTmpPos = tmp; - newData = true; - mNextLayer = null; + this.newData = true; + if (!(positionChanged || tilesChanged)) return; } diff --git a/src/org/oscim/utils/IOUtils.java b/src/org/oscim/utils/IOUtils.java new file mode 100644 index 00000000..920db97e --- /dev/null +++ b/src/org/oscim/utils/IOUtils.java @@ -0,0 +1,48 @@ +/* + * Copyright 2010, 2011, 2012 mapsforge.org + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . + */ +package org.oscim.utils; + +import java.io.Closeable; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A utility class with IO-specific helper methods. + */ +public final class IOUtils { + private static final Logger LOGGER = Logger.getLogger(IOUtils.class.getName()); + + /** + * Invokes the {@link Closeable#close()} method on the given object. If an {@link IOException} occurs during the + * method call, it will be caught and logged on level {@link Level#WARNING}. + * + * @param closeable + * the data source which should be closed (may be null). + */ + public static void closeQuietly(Closeable closeable) { + try { + if (closeable != null) { + closeable.close(); + } + } catch (IOException e) { + LOGGER.log(Level.FINE, e.getMessage(), e); + } + } + + private IOUtils() { + throw new IllegalStateException(); + } +} diff --git a/src/org/oscim/utils/pool/SyncPool.java b/src/org/oscim/utils/pool/SyncPool.java index b2dcd309..553aad4d 100644 --- a/src/org/oscim/utils/pool/SyncPool.java +++ b/src/org/oscim/utils/pool/SyncPool.java @@ -21,26 +21,45 @@ public abstract class SyncPool> { protected T pool; - public SyncPool(){ + public SyncPool() { maxFill = 100; + fill = 0; + count = 0; } public SyncPool(int maxItemsInPool) { maxFill = maxItemsInPool; fill = 0; + count = 0; + } + + public int getCount() { + return count; + } + + public int getFill() { + return fill; } /** * @param items number of initial items */ - public void init(int items){ + public void init(int items) { + count = items; + fill = items; + } + + /** + * @param item set initial state + */ + protected void clearItem(T item) { } /** * @param item release resources */ - protected void clearItem(T item) { + protected void freeItem(T item) { } @@ -59,7 +78,8 @@ public abstract class SyncPool> { item.next = pool; pool = item; } - } else{ + } else { + freeItem(item); count--; } } @@ -68,69 +88,36 @@ public abstract class SyncPool> { if (item == null) return; - if (fill > maxFill) - while (item != null) { - clearItem(item); + if (fill > maxFill) { + while (item != null) { + clearItem(item); + freeItem(item); + count--; - item = item.next; - count--; - } - - if (item == null) + item = item.next; + } return; + } synchronized (this) { while (item != null) { T next = item.next; + clearItem(item); + fill++; item.next = pool; pool = item; - fill++; item = next; } } } - // remove 'item' from 'list' and add back to pool - public T release(T list, T item) { - if (item == null) - return list; - - T ret = list; - - clearItem(item); - - if (item == list) { - ret = item.next; - } else { - for (T prev = list, it = list.next; it != null; it = it.next) { - if (it == item) { - prev.next = it.next; - } - prev = it; - } - } - - if (fill < maxFill) { - synchronized (this) { - fill++; - - item.next = pool; - pool = item; - } - } else{ - count--; - } - - return ret; - } - public T get() { synchronized (this) { - if (pool == null){ + if (pool == null) { count++; return createItem(); } diff --git a/src/org/oscim/view/MapView.java b/src/org/oscim/view/MapView.java index 141eafac..27a8f9ce 100644 --- a/src/org/oscim/view/MapView.java +++ b/src/org/oscim/view/MapView.java @@ -23,6 +23,7 @@ import org.oscim.core.MapPosition; import org.oscim.core.Tile; import org.oscim.database.MapOptions; import org.oscim.layers.Layer; +import org.oscim.layers.tile.BitmapTileLayer; import org.oscim.layers.tile.MapTileLayer; import org.oscim.layers.tile.MapTileLoader; import org.oscim.overlay.BuildingOverlay; @@ -152,6 +153,18 @@ public class MapView extends RelativeLayout { return baseLayer; } + public void setBackgroundMap(BitmapTileLayer tileLayer) { + mLayerManager.add(0, tileLayer); + } + + public MapTileLayer setBaseMap(BitmapTileLayer tileLayer) { + mLayerManager.add(0, new MapEventLayer(this)); + mLayerManager.add(1, tileLayer); + + //mRotationEnabled = true; + return null; + } + void destroy() { mLayerManager.destroy(); }