added BitmapTileLayer, and TileSource interface from mapsforge

This commit is contained in:
Hannes Janetzek 2013-04-24 12:15:20 +02:00
parent 34065efb93
commit ae993eccce
19 changed files with 777 additions and 106 deletions

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<TileLoader> {
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;
}
};
}
}

View File

@ -19,9 +19,6 @@ import org.oscim.utils.PausableThread;
public abstract class TileLoader extends PausableThread { public abstract class TileLoader extends PausableThread {
private static int id; private static int id;
public interface Factory<T extends TileLoader>{
T create(JobQueue jobQueue, TileManager tileManager);
}
private final String THREAD_NAME; private final String THREAD_NAME;
private final JobQueue mJobQueue; private final JobQueue mJobQueue;

View File

@ -22,6 +22,7 @@ import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.renderer.GLRenderer; import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.GLRenderer.Matrices; import org.oscim.renderer.GLRenderer.Matrices;
import org.oscim.renderer.layer.BitmapRenderer;
import org.oscim.renderer.layer.Layer; import org.oscim.renderer.layer.Layer;
import org.oscim.renderer.layer.LineRenderer; import org.oscim.renderer.layer.LineRenderer;
import org.oscim.renderer.layer.LineTexRenderer; 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' // clear clip-region and could also draw 'fade-effect'
if (mFaded) if (mFaded)
PolygonRenderer.drawOver(m, true, 0x22000000); PolygonRenderer.drawOver(m, true, 0x22000000);

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}

View File

@ -243,8 +243,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
| GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT
| GLES20.GL_STENCIL_BUFFER_BIT); | GLES20.GL_STENCIL_BUFFER_BIT);
boolean tilesChanged = true; boolean tilesChanged = false;
boolean positionChanged = true; boolean positionChanged = false;
// get current MapPosition, set mBoxCoords (mapping of screen to model // get current MapPosition, set mBoxCoords (mapping of screen to model
// coordinates) // coordinates)
@ -253,7 +253,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
synchronized (mMapViewPosition) { synchronized (mMapViewPosition) {
mMapViewPosition.updateAnimation(); mMapViewPosition.updateAnimation();
positionChanged |= mMapViewPosition.getMapPosition(pos); positionChanged = mMapViewPosition.getMapPosition(pos);
if (positionChanged) if (positionChanged)
mMapViewPosition.getMapViewProjection(mBoxCoords); mMapViewPosition.getMapViewProjection(mBoxCoords);

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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);"
+ "}";
}

View File

@ -28,6 +28,7 @@ public class Layers {
LineTexRenderer.init(); LineTexRenderer.init();
PolygonRenderer.init(); PolygonRenderer.init();
TextureRenderer.init(); TextureRenderer.init();
BitmapRenderer.init();
TextureItem.init(10); TextureItem.init(10);
} }

View File

@ -102,7 +102,7 @@ public final class SymbolLayer extends TextureLayer {
float x = 0; float x = 0;
float y = 0; float y = 0;
TextureItem to = TextureItem.pool.get(); TextureItem to = TextureItem.get(true);
textures = to; textures = to;
mCanvas.setBitmap(to.bitmap); mCanvas.setBitmap(to.bitmap);
@ -138,7 +138,7 @@ public final class SymbolLayer extends TextureLayer {
offsetIndices = numIndices; offsetIndices = numIndices;
curIndices = 0; curIndices = 0;
to.next = TextureItem.pool.get(); to.next = TextureItem.get(true);
to = to.next; to = to.next;
mCanvas.setBitmap(to.bitmap); mCanvas.setBitmap(to.bitmap);
@ -247,7 +247,8 @@ public final class SymbolLayer extends TextureLayer {
@Override @Override
protected void clear() { protected void clear() {
TextureItem.pool.releaseAll(textures); TextureItem.releaseAll(textures);
SymbolItem.pool.releaseAll(symbols); SymbolItem.pool.releaseAll(symbols);
VertexItem.pool.releaseAll(vertexItems); VertexItem.pool.releaseAll(vertexItems);
textures = null; textures = null;

View File

@ -17,8 +17,6 @@ package org.oscim.renderer.layer;
import static org.oscim.renderer.GLRenderer.COORD_SCALE; 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_HEIGHT;
import static org.oscim.renderer.layer.TextureItem.TEXTURE_WIDTH; import static org.oscim.renderer.layer.TextureItem.TEXTURE_WIDTH;
import android.graphics.Canvas; import android.graphics.Canvas;
public final class TextLayer extends TextureLayer { public final class TextLayer extends TextureLayer {
@ -91,7 +89,7 @@ public final class TextLayer extends TextureLayer {
float y = 0; float y = 0;
float yy; float yy;
TextureItem to = TextureItem.pool.get(); TextureItem to = TextureItem.get(true);
textures = to; textures = to;
mCanvas.setBitmap(to.bitmap); mCanvas.setBitmap(to.bitmap);
@ -113,7 +111,7 @@ public final class TextLayer extends TextureLayer {
to.vertices = (short) (numIndices - offsetIndices); to.vertices = (short) (numIndices - offsetIndices);
offsetIndices = numIndices; offsetIndices = numIndices;
to.next = TextureItem.pool.get(); to.next = TextureItem.get(true);
to = to.next; to = to.next;
mCanvas.setBitmap(to.bitmap); mCanvas.setBitmap(to.bitmap);
@ -266,7 +264,7 @@ public final class TextLayer extends TextureLayer {
@Override @Override
protected void clear() { protected void clear() {
TextureItem.pool.releaseAll(textures); TextureItem.releaseAll(textures);
TextItem.pool.releaseAll(labels); TextItem.pool.releaseAll(labels);
VertexItem.pool.releaseAll(vertexItems); VertexItem.pool.releaseAll(vertexItems);
textures = null; textures = null;

View File

@ -16,6 +16,7 @@ package org.oscim.renderer.layer;
import java.util.ArrayList; import java.util.ArrayList;
import org.oscim.utils.GlUtils;
import org.oscim.utils.pool.Inlist; import org.oscim.utils.pool.Inlist;
import org.oscim.utils.pool.SyncPool; import org.oscim.utils.pool.SyncPool;
@ -44,15 +45,30 @@ public class TextureItem extends Inlist<TextureItem> {
// temporary Bitmap // temporary Bitmap
public Bitmap bitmap; public Bitmap bitmap;
boolean ownBitmap;
TextureItem(int id) { TextureItem(int id) {
this.id = id; this.id = id;
} }
public final static SyncPool<TextureItem> pool = new SyncPool<TextureItem>() { 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<TextureItem> pool = new SyncPool<TextureItem>(20) {
@Override @Override
public void init(int num) { public void init(int num) {
this.pool = null; super.init(num);
int[] textureIds = new int[num]; int[] textureIds = new int[num];
GLES20.glGenTextures(num, textureIds, 0); GLES20.glGenTextures(num, textureIds, 0);
@ -60,22 +76,10 @@ public class TextureItem extends Inlist<TextureItem> {
for (int i = 1; i < num; i++) { for (int i = 1; i < num; i++) {
initTexture(textureIds[i]); initTexture(textureIds[i]);
TextureItem to = new TextureItem(textureIds[i]); TextureItem to = new TextureItem(textureIds[i]);
pool = Inlist.push(pool, to);
to.next = this.pool;
this.pool = to;
} }
} }
@Override
public TextureItem get() {
TextureItem it = super.get();
it.bitmap = TextureItem.getBitmap();
it.bitmap.eraseColor(Color.TRANSPARENT);
return it;
}
@Override @Override
protected TextureItem createItem() { protected TextureItem createItem() {
return new TextureItem(-1); return new TextureItem(-1);
@ -83,10 +87,22 @@ public class TextureItem extends Inlist<TextureItem> {
@Override @Override
protected void clearItem(TextureItem it) { 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<Integer> mFreeTextures = new ArrayList<Integer>();
private static ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(10); private static ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(10);
public final static int TEXTURE_WIDTH = 512; public final static int TEXTURE_WIDTH = 512;
@ -94,6 +110,27 @@ public class TextureItem extends Inlist<TextureItem> {
private static int mBitmapFormat; private static int mBitmapFormat;
private static int mBitmapType; 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. * This function may only be used in GLRenderer Thread.
@ -102,23 +139,32 @@ public class TextureItem extends Inlist<TextureItem> {
*/ */
public static void uploadTexture(TextureItem to) { public static void uploadTexture(TextureItem to) {
if (TextureRenderer.debug) // free unused textures, find a better place for this TODO
Log.d(TAG, "upload texture " + to.id); 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) { if (to.id < 0) {
mTexCnt++;
int[] textureIds = new int[1]; int[] textureIds = new int[1];
GLES20.glGenTextures(1, textureIds, 0); GLES20.glGenTextures(1, textureIds, 0);
to.id = textureIds[0]; to.id = textureIds[0];
initTexture(to.id); initTexture(to.id);
if (TextureRenderer.debug) 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, uploadTexture(to, to.bitmap, mBitmapFormat, mBitmapType,
TEXTURE_WIDTH, TEXTURE_HEIGHT); TEXTURE_WIDTH, TEXTURE_HEIGHT);
TextureItem.releaseBitmap(to); if (!to.ownBitmap)
TextureItem.releaseBitmap(to);
} }
public static void uploadTexture(TextureItem to, Bitmap bitmap, public static void uploadTexture(TextureItem to, Bitmap bitmap,
@ -129,13 +175,21 @@ public class TextureItem extends Inlist<TextureItem> {
return; return;
} }
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, to.id); 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); 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); GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, format, bitmap, type, 0);
to.width = w; to.width = w;
to.height = h; to.height = h;
} }
if (TextureRenderer.debug)
GlUtils.checkGlError(TAG);
} }
static void initTexture(int id) { static void initTexture(int id) {
@ -166,6 +220,8 @@ public class TextureItem extends Inlist<TextureItem> {
mBitmapFormat = GLUtils.getInternalFormat(mBitmaps.get(0)); mBitmapFormat = GLUtils.getInternalFormat(mBitmaps.get(0));
mBitmapType = GLUtils.getType(mBitmaps.get(0)); mBitmapType = GLUtils.getType(mBitmaps.get(0));
mTexCnt = num;
} }
static Bitmap getBitmap() { static Bitmap getBitmap() {
@ -186,14 +242,4 @@ public class TextureItem extends Inlist<TextureItem> {
return mBitmaps.remove(size - 1); return mBitmaps.remove(size - 1);
} }
} }
static void releaseBitmap(TextureItem it) {
synchronized (mBitmaps) {
if (it.bitmap != null) {
mBitmaps.add(it.bitmap);
it.bitmap = null;
}
}
}
} }

View File

@ -20,8 +20,8 @@ import static org.oscim.renderer.layer.TextureItem.TEXTURE_HEIGHT;
import static org.oscim.renderer.layer.TextureItem.TEXTURE_WIDTH; import static org.oscim.renderer.layer.TextureItem.TEXTURE_WIDTH;
import org.oscim.renderer.GLRenderer; import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.GLState;
import org.oscim.renderer.GLRenderer.Matrices; import org.oscim.renderer.GLRenderer.Matrices;
import org.oscim.renderer.GLState;
import org.oscim.utils.GlUtils; import org.oscim.utils.GlUtils;
import android.opengl.GLES20; import android.opengl.GLES20;
@ -30,6 +30,7 @@ import android.opengl.GLES20;
* @author Hannes Janetzek * @author Hannes Janetzek
*/ */
public final class TextureRenderer { public final class TextureRenderer {
//private final static String TAG = TextureRenderer.class.getName();
public final static boolean debug = false; public final static boolean debug = false;
private static int mTextureProgram; private static int mTextureProgram;
@ -78,15 +79,15 @@ public final class TextureRenderer {
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, GLRenderer.mQuadIndicesID); 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; int maxVertices = GLRenderer.maxQuads * INDICES_PER_SPRITE;
// draw up to maxVertices in each iteration // 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) // 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.glVertexAttribPointer(hTextureVertex, 4,
GLES20.GL_SHORT, false, 12, off); GLES20.GL_SHORT, false, 12, off);
@ -94,7 +95,7 @@ public final class TextureRenderer {
GLES20.glVertexAttribPointer(hTextureTexCoord, 2, GLES20.glVertexAttribPointer(hTextureTexCoord, 2,
GLES20.GL_SHORT, false, 12, off + 8); GLES20.GL_SHORT, false, 12, off + 8);
int numVertices = to.vertices - i; int numVertices = ti.vertices - i;
if (numVertices > maxVertices) if (numVertices > maxVertices)
numVertices = maxVertices; numVertices = maxVertices;

View File

@ -33,7 +33,6 @@ import org.oscim.core.Tile;
import org.oscim.graphics.Color; import org.oscim.graphics.Color;
import org.oscim.graphics.Paint.Cap; import org.oscim.graphics.Paint.Cap;
import org.oscim.layers.tile.MapTile; import org.oscim.layers.tile.MapTile;
import org.oscim.layers.tile.MapTile;
import org.oscim.layers.tile.TileRenderLayer; import org.oscim.layers.tile.TileRenderLayer;
import org.oscim.layers.tile.TileSet; import org.oscim.layers.tile.TileSet;
import org.oscim.renderer.BufferObject; import org.oscim.renderer.BufferObject;
@ -61,7 +60,7 @@ import android.opengl.GLES20;
import android.os.SystemClock; import android.os.SystemClock;
public class TextOverlay extends BasicOverlay { 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_CAPTION_DIST = 5;
private final static float MIN_WAY_DIST = 3; private final static float MIN_WAY_DIST = 3;
@ -179,7 +178,7 @@ public class TextOverlay extends BasicOverlay {
mRun = false; mRun = false;
if (updateLabels()) { if (updateLabels()) {
mMapView.redrawMap(true); mMapView.render();
} else { } else {
mRun = true; mRun = true;
} }
@ -695,14 +694,15 @@ public class TextOverlay extends BasicOverlay {
// set new TextLayer to be uploaded and rendered // set new TextLayer to be uploaded and rendered
layers.textureLayers = mNextLayer; layers.textureLayers = mNextLayer;
mNextLayer = null;
// make the 'labeled' MapPosition current // make the 'labeled' MapPosition current
MapPosition tmp = mMapPosition; MapPosition tmp = mMapPosition;
mMapPosition = mTmpPos; mMapPosition = mTmpPos;
mTmpPos = tmp; mTmpPos = tmp;
newData = true; this.newData = true;
mNextLayer = null;
if (!(positionChanged || tilesChanged)) if (!(positionChanged || tilesChanged))
return; return;
} }

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@ -21,26 +21,45 @@ public abstract class SyncPool<T extends Inlist<T>> {
protected T pool; protected T pool;
public SyncPool(){ public SyncPool() {
maxFill = 100; maxFill = 100;
fill = 0;
count = 0;
} }
public SyncPool(int maxItemsInPool) { public SyncPool(int maxItemsInPool) {
maxFill = maxItemsInPool; maxFill = maxItemsInPool;
fill = 0; fill = 0;
count = 0;
}
public int getCount() {
return count;
}
public int getFill() {
return fill;
} }
/** /**
* @param items number of initial items * @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 * @param item release resources
*/ */
protected void clearItem(T item) { protected void freeItem(T item) {
} }
@ -59,7 +78,8 @@ public abstract class SyncPool<T extends Inlist<T>> {
item.next = pool; item.next = pool;
pool = item; pool = item;
} }
} else{ } else {
freeItem(item);
count--; count--;
} }
} }
@ -68,69 +88,36 @@ public abstract class SyncPool<T extends Inlist<T>> {
if (item == null) if (item == null)
return; return;
if (fill > maxFill) if (fill > maxFill) {
while (item != null) { while (item != null) {
clearItem(item); clearItem(item);
freeItem(item);
count--;
item = item.next; item = item.next;
count--; }
}
if (item == null)
return; return;
}
synchronized (this) { synchronized (this) {
while (item != null) { while (item != null) {
T next = item.next; T next = item.next;
clearItem(item); clearItem(item);
fill++;
item.next = pool; item.next = pool;
pool = item; pool = item;
fill++;
item = next; 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() { public T get() {
synchronized (this) { synchronized (this) {
if (pool == null){ if (pool == null) {
count++; count++;
return createItem(); return createItem();
} }

View File

@ -23,6 +23,7 @@ import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.database.MapOptions; import org.oscim.database.MapOptions;
import org.oscim.layers.Layer; import org.oscim.layers.Layer;
import org.oscim.layers.tile.BitmapTileLayer;
import org.oscim.layers.tile.MapTileLayer; import org.oscim.layers.tile.MapTileLayer;
import org.oscim.layers.tile.MapTileLoader; import org.oscim.layers.tile.MapTileLoader;
import org.oscim.overlay.BuildingOverlay; import org.oscim.overlay.BuildingOverlay;
@ -152,6 +153,18 @@ public class MapView extends RelativeLayout {
return baseLayer; 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() { void destroy() {
mLayerManager.destroy(); mLayerManager.destroy();
} }