add osmdroid overlays + bonuspack

This commit is contained in:
Hannes Janetzek
2012-10-27 13:35:51 +02:00
parent 65a6f91f3c
commit ab5962d56c
114 changed files with 9562 additions and 1636 deletions

View File

@@ -25,7 +25,7 @@ import static android.opengl.GLES20.GL_POLYGON_OFFSET_FILL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import javax.microedition.khronos.egl.EGLConfig;
@@ -35,8 +35,7 @@ import org.oscim.core.MapPosition;
import org.oscim.core.Tile;
import org.oscim.renderer.layer.Layer;
import org.oscim.renderer.layer.Layers;
import org.oscim.renderer.overlays.Overlay;
import org.oscim.renderer.overlays.OverlayText;
import org.oscim.renderer.overlays.RenderOverlay;
import org.oscim.theme.RenderTheme;
import org.oscim.utils.GlUtils;
import org.oscim.view.MapView;
@@ -61,7 +60,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
static int CACHE_TILES = CACHE_TILES_MAX;
private final MapView mMapView;
private static MapView mMapView;
static int mWidth, mHeight;
private static MapViewPosition mMapViewPosition;
@@ -177,10 +176,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
}
};
/**
* @param mapView
* the MapView
*/
/** @param mapView
* the MapView */
public GLRenderer(MapView mapView) {
mMapView = mapView;
@@ -213,15 +210,15 @@ public class GLRenderer implements GLSurfaceView.Renderer {
shortBuffer[i].put(mFillCoords, 0, 8);
}
mOverlays = new ArrayList<Overlay>();
// overlays = new ArrayList<RenderOverlay>();
// mOverlays.add(new OverlayGrid(mapView));
// mOverlays.add(new OverlayTest(mapView));
mOverlays.add(new OverlayText(mapView));
// overlays.add(new OverlayText(mapView));
}
private static ArrayList<Overlay> mOverlays;
// private static ArrayList<RenderOverlay> overlays;
public static void setRenderTheme(RenderTheme t) {
mClearColor = GlUtils.colorToFloat(t.getMapBackground());
@@ -234,7 +231,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
int newSize = layers.getSize();
if (newSize == 0) {
Log.d(TAG, "empty");
// FIXME why are there so many tiles empty?
// Log.d(TAG, "empty");
return true;
}
@@ -315,14 +313,14 @@ public class GLRenderer implements GLSurfaceView.Renderer {
return tile.isReady;
}
private static boolean uploadOverlayData(Overlay overlay) {
private static boolean uploadOverlayData(RenderOverlay renderOverlay) {
if (uploadLayers(overlay.layers, overlay.vbo, true))
overlay.isReady = true;
if (uploadLayers(renderOverlay.layers, renderOverlay.vbo, true))
renderOverlay.isReady = true;
overlay.newData = false;
renderOverlay.newData = false;
return overlay.isReady;
return renderOverlay.isReady;
}
private static void checkBufferUsage() {
@@ -384,7 +382,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
public void onDrawFrame(GL10 glUnused) {
// prevent main thread recreating all tiles (updateMap)
// while rendering is going.
// while rendering is going on.
drawlock.lock();
try {
draw();
@@ -421,9 +419,11 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// get current tiles to draw
mDrawTiles = TileManager.getActiveTiles(mDrawTiles);
// FIXME what if only drawing overlays?
if (mDrawTiles == null || mDrawTiles.cnt == 0) {
return;
}
boolean tilesChanged = false;
// check if the tiles have changed...
if (serial != mDrawTiles.serial) {
@@ -450,14 +450,13 @@ public class GLRenderer implements GLSurfaceView.Renderer {
float div = scaleDiv(tiles[0]);
// transform screen coordinates to tile coordinates
float s = Tile.TILE_SIZE;
float scale = mapPosition.scale / div;
float px = (float) mapPosition.x * div;
float py = (float) mapPosition.y * div;
for (int i = 0; i < 8; i += 2) {
coords[i + 0] = (px + coords[i + 0] / scale) / s;
coords[i + 1] = (py + coords[i + 1] / scale) / s;
coords[i + 0] = (px + coords[i + 0] / scale) / Tile.TILE_SIZE;
coords[i + 1] = (py + coords[i + 1] / scale) / Tile.TILE_SIZE;
}
mHolderCount = 0;
@@ -514,11 +513,11 @@ public class GLRenderer implements GLSurfaceView.Renderer {
tilesChanged |= (uploadCnt > 0);
// if (changed || tilesChanged) {
for (Overlay overlay : mOverlays) {
overlay.update(changed, tilesChanged);
}
// }
// update overlays
List<RenderOverlay> overlays = mMapView.getOverlayManager().getRenderLayers();
for (int i = 0, n = overlays.size(); i < n; i++)
overlays.get(i).update(mMapPosition, changed, tilesChanged);
GLES20.glEnable(GL_DEPTH_TEST);
GLES20.glEnable(GL_POLYGON_OFFSET_FILL);
@@ -538,7 +537,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (t.isVisible && !t.isReady && (t.holder == null))
drawProxyTile(t);
}
// GlUtils.checkGlError("end draw");
GLES20.glDisable(GL_POLYGON_OFFSET_FILL);
GLES20.glDisable(GL_DEPTH_TEST);
@@ -549,22 +547,25 @@ public class GLRenderer implements GLSurfaceView.Renderer {
GLES20.glEnable(GL_BLEND);
// call overlay renderer
for (Overlay overlay : mOverlays) {
if (overlay.newData) {
if (overlay.vbo == null)
overlay.vbo = BufferObject.get();
for (int i = 0, n = overlays.size(); i < n; i++) {
RenderOverlay renderOverlay = overlays.get(i);
if (overlay.vbo == null)
continue;
if (renderOverlay.newData) {
if (renderOverlay.vbo == null) {
renderOverlay.vbo = BufferObject.get();
if (uploadOverlayData(overlay))
overlay.isReady = true;
if (renderOverlay.vbo == null)
continue;
}
if (uploadOverlayData(renderOverlay))
renderOverlay.isReady = true;
}
if (!overlay.isReady)
continue;
// setMatrix(mMVPMatrix, overlay);
overlay.render(mMapPosition, mMVPMatrix, mProjMatrix);
if (renderOverlay.isReady) {
// setMatrix(mMVPMatrix, overlay);
renderOverlay.render(mMapPosition, mMVPMatrix, mProjMatrix);
}
}
if (MapView.debugFrameTime) {
@@ -594,6 +595,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mapPosition.viewMatrix, 0);
PolygonRenderer.debugDraw(mMVPMatrix, mDebugCoords, 1);
}
// mMapView.getOverlayManager().onUpdate(mMapPosition);
}
// used to not draw a tile twice per frame.

View File

@@ -32,7 +32,7 @@ public class GLView extends GLSurfaceView {
setEGLConfigChooser(new GlConfigChooser());
setEGLContextClientVersion(2);
// setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
mRenderer = new GLRenderer(mMapView);
setRenderer(mRenderer);

View File

@@ -44,6 +44,7 @@ class QuadTree {
static boolean remove(MapTile t) {
if (t.rel == null) {
// Bad Things(tm) happened
Log.d(TAG, "already removed " + t);
return true;
}

View File

@@ -13,12 +13,9 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ported from Polymaps: Layer.js Copyright (c) 2010, SimpleGeo and Stamen Design */
package org.oscim.renderer;
import android.util.FloatMath;
import android.util.Log;
public abstract class ScanBox {
@@ -31,16 +28,14 @@ public abstract class ScanBox {
this.y0 = y0;
this.x1 = x1;
this.y1 = y1;
dx = x1 - x0;
dy = y1 - y0;
} else {
this.x0 = x1;
this.y0 = y1;
this.x1 = x0;
this.y1 = y0;
dx = x0 - x1;
dy = y0 - y1;
}
this.dx = this.x1 - this.x0;
this.dy = this.y1 - this.y0;
}
}
@@ -49,33 +44,32 @@ public abstract class ScanBox {
private Edge ca = new Edge();
protected byte mZoom;
void scan(float[] coords, byte zoom) {
abstract void setVisible(int y, int x1, int x2);
public void scan(float[] coords, byte zoom) {
mZoom = zoom;
// top-left -> top-right
ab.set(coords[0], coords[1], coords[2], coords[3]);
// top-right -> bottom-right
bc.set(coords[2], coords[3], coords[4], coords[5]);
// bottom-right -> bottom-left
ca.set(coords[4], coords[5], coords[0], coords[1]);
scanTriangle();
ab.set(coords[4], coords[5], coords[6], coords[7]);
bc.set(coords[6], coords[7], coords[0], coords[1]);
ca.set(coords[0], coords[1], coords[4], coords[5]);
scanTriangle();
}
// top-left -> bottom-right
ab.set(coords[0], coords[1], coords[4], coords[5]);
// bottom-right -> bottom-left
bc.set(coords[4], coords[5], coords[6], coords[7]);
// bottom-left -> top-left
ca.set(coords[6], coords[7], coords[0], coords[1]);
/**
* @param y
* ...
* @param x1
* ...
* @param x2
* ...
*/
void setVisible(int y, int x1, int x2) {
scanTriangle();
}
private void scanTriangle() {
// sort so that ca.dy > bc.dy > ab.dy
if (ab.dy > bc.dy) {
Edge t = ab;
ab = bc;
@@ -91,23 +85,21 @@ public abstract class ScanBox {
bc = ca;
ca = t;
}
// ca.dy > bc.dy > ab.dy
// shouldnt be possible, anyway
if (ca.dy == 0)
return;
if (ab.dy != 0)
if (ab.dy > 0.1)
scanSpans(ca, ab);
if (bc.dy != 0)
if (bc.dy > 0.1)
scanSpans(ca, bc);
}
// FIXME
private static final int MAX_SLOPE = 4;
private void scanSpans(Edge e0, Edge e1) {
// scan the y-range of the edge with less dy
int y0 = (int) Math.max(0, FloatMath.floor(e1.y0));
int y1 = (int) Math.min((1 << mZoom), FloatMath.ceil(e1.y1));
@@ -131,41 +123,99 @@ public abstract class ScanBox {
float m0 = e0.dx / e0.dy;
float m1 = e1.dx / e1.dy;
// still needed?
if (m0 > MAX_SLOPE)
m0 = MAX_SLOPE;
else if (m0 < -MAX_SLOPE)
m0 = -MAX_SLOPE;
// FIXME, something is wrong here, with a steep angle
// 'fill' can shoot far over the area in one direction
int maxSlope = 8;
if (m0 > maxSlope)
m0 = maxSlope;
else if (m0 < -maxSlope)
m0 = -maxSlope;
if (m1 > MAX_SLOPE)
m1 = MAX_SLOPE;
else if (m1 < -MAX_SLOPE)
m1 = -MAX_SLOPE;
if (m1 > maxSlope)
m1 = maxSlope;
else if (m1 < -maxSlope)
m1 = -maxSlope;
// e0 goes to the right, e1 to the left
int d0 = e0.dx > 0 ? 1 : 0; // use y + 1 to compute x0
int d1 = e1.dx < 0 ? 1 : 0; // use y + 1 to compute x1
float x0, x1, dy;
float dy;
for (int y = y0; y < y1; y++) {
dy = y + d0 - e0.y0;
if (e0.dy < dy)
dy = d0 + y - e0.y0;
if (dy > e0.dy)
dy = e0.dy;
x0 = e0.x0 + m0 * dy;
x0 = FloatMath.ceil(x0);
float x0 = FloatMath.ceil(e0.x0 + m0 * dy);
dy = y + d1 - e1.y0;
if (e1.dy < dy)
dy = d1 + y - e1.y0;
if (dy > e1.dy)
dy = e1.dy;
x1 = e1.x0 + m1 * dy;
x1 = FloatMath.floor(x1);
float x1 = FloatMath.floor(e1.x0 + m1 * dy);
if (x1 > x0)
Log.d("...", "X set visible" + y + " " + x1 + "/" + x0);
setVisible(y, (int) x1, (int) x0);
if (x1 < x0)
setVisible(y, (int) x1, (int) x0);
}
}
/*
* ported from Polymaps: Layer.js Copyright (c) 2010, SimpleGeo and Stamen
* Design
*/
// // scan-line conversion
// function edge(a, b) {
// if (a.row > b.row) { var t = a; a = b; b = t; }
// return {
// x0: a.column,
// y0: a.row,
// x1: b.column,
// y1: b.row,
// dx: b.column - a.column,
// dy: b.row - a.row
// };
// }
//
// // scan-line conversion
// function scanSpans(e0, e1, ymin, ymax, scanLine) {
// var y0 = Math.max(ymin, Math.floor(e1.y0)),
// y1 = Math.min(ymax, Math.ceil(e1.y1));
//
// // sort edges by x-coordinate
// if ((e0.x0 == e1.x0 && e0.y0 == e1.y0)
// ? (e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1)
// : (e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0)) {
// var t = e0; e0 = e1; e1 = t;
// }
//
// // scan lines!
// var m0 = e0.dx / e0.dy,
// m1 = e1.dx / e1.dy,
// d0 = e0.dx > 0, // use y + 1 to compute x0
// d1 = e1.dx < 0; // use y + 1 to compute x1
// for (var y = y0; y < y1; y++) {
// var x0 = m0 * Math.max(0, Math.min(e0.dy, y + d0 - e0.y0)) + e0.x0,
// x1 = m1 * Math.max(0, Math.min(e1.dy, y + d1 - e1.y0)) + e1.x0;
// scanLine(Math.floor(x1), Math.ceil(x0), y);
// }
// }
//
// // scan-line conversion
// function scanTriangle(a, b, c, ymin, ymax, scanLine) {
// var ab = edge(a, b),
// bc = edge(b, c),
// ca = edge(c, a);
//
// // sort edges by y-length
// if (ab.dy > bc.dy) { var t = ab; ab = bc; bc = t; }
// if (ab.dy > ca.dy) { var t = ab; ab = ca; ca = t; }
// if (bc.dy > ca.dy) { var t = bc; bc = ca; ca = t; }
//
// // scan span! scan span!
// if (ab.dy) scanSpans(ca, ab, ymin, ymax, scanLine);
// if (bc.dy) scanSpans(ca, bc, ymin, ymax, scanLine);
// }
}

View File

@@ -14,8 +14,9 @@
*/
package org.oscim.renderer;
import java.util.ArrayList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.opengl.GLES20;
import android.opengl.GLUtils;
@@ -24,11 +25,12 @@ import android.util.Log;
public class TextureObject {
private static TextureObject pool;
private static ArrayList<Bitmap> mBitmaps;
// shared bitmap and canvas for default texture size
public final static int TEXTURE_WIDTH = 256;
public final static int TEXTURE_HEIGHT = 256;
private static Bitmap[] mBitmap;
private static Canvas[] mCanvas;
private static int mBitmapFormat;
private static int mBitmapType;
private static int objectCount = 10;
@@ -37,22 +39,38 @@ public class TextureObject {
TextureObject to;
if (pool == null) {
init(10);
objectCount += 10;
Log.d("...", "textures: " + objectCount);
objectCount += 1;
if (TextureRenderer.debug)
Log.d("...", "textures: " + objectCount);
pool = new TextureObject(-1);
}
to = pool;
pool = pool.next;
to.next = null;
to.bitmap = getBitmap();
to.bitmap.eraseColor(Color.TRANSPARENT);
if (TextureRenderer.debug)
Log.d("...", "get texture " + to.id + " " + to.bitmap);
return to;
}
public static synchronized void release(TextureObject to) {
while (to != null) {
if (TextureRenderer.debug)
Log.d("...", "release texture " + to.id);
TextureObject next = to.next;
if (to.bitmap != null) {
mBitmaps.add(to.bitmap);
to.bitmap = null;
}
to.next = pool;
pool = to;
@@ -60,6 +78,26 @@ public class TextureObject {
}
}
public static synchronized void uploadTexture(TextureObject to) {
if (TextureRenderer.debug)
Log.d("...", "upload texture " + to.id);
if (to.id < 0) {
int[] textureIds = new int[1];
GLES20.glGenTextures(1, textureIds, 0);
to.id = textureIds[0];
initTexture(to.id);
if (TextureRenderer.debug)
Log.d("...", "new texture " + to.id);
}
uploadTexture(to, to.bitmap, mBitmapFormat, mBitmapType,
TEXTURE_WIDTH, TEXTURE_HEIGHT);
mBitmaps.add(to.bitmap);
to.bitmap = null;
}
public static void uploadTexture(TextureObject to, Bitmap bitmap,
int format, int type, int w, int h) {
@@ -77,73 +115,74 @@ public class TextureObject {
}
}
static void initTexture(int id) {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, id);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE); // Set U Wrapping
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE); // Set V Wrapping
}
static void init(int num) {
pool = null;
TextureObject to;
int[] textureIds = new int[num];
GLES20.glGenTextures(num, textureIds, 0);
for (int i = 1; i < num; i++) {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[i]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE); // Set U Wrapping
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE); // Set V Wrapping
initTexture(textureIds[i]);
to = new TextureObject(textureIds[i]);
to.next = pool;
pool = to;
}
mBitmap = new Bitmap[4];
mCanvas = new Canvas[4];
mBitmaps = new ArrayList<Bitmap>(10);
for (int i = 0; i < 4; i++) {
mBitmap[i] = Bitmap.createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT,
Bitmap bitmap = Bitmap.createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT,
Bitmap.Config.ARGB_8888);
mCanvas[i] = new Canvas(mBitmap[i]);
mBitmaps.add(bitmap);
}
mBitmapFormat = GLUtils.getInternalFormat(mBitmap[0]);
mBitmapType = GLUtils.getType(mBitmap[0]);
mBitmapFormat = GLUtils.getInternalFormat(mBitmaps.get(0));
mBitmapType = GLUtils.getType(mBitmaps.get(0));
}
private static int curCanvas = 0;
private static Bitmap getBitmap() {
int size = mBitmaps.size();
if (size == 0) {
for (int i = 0; i < 4; i++) {
Bitmap bitmap = Bitmap.createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT,
Bitmap.Config.ARGB_8888);
public static Canvas getCanvas() {
curCanvas = ++curCanvas % 4;
mBitmap[curCanvas].eraseColor(Color.TRANSPARENT);
return mCanvas[curCanvas];
}
public static TextureObject uploadCanvas(short offset, short indices) {
TextureObject to = get();
uploadTexture(to, mBitmap[curCanvas],
mBitmapFormat, mBitmapType,
TEXTURE_WIDTH, TEXTURE_HEIGHT);
to.offset = offset;
to.vertices = (short) (indices - offset);
return to;
mBitmaps.add(bitmap);
}
size = 4;
}
return mBitmaps.remove(size - 1);
}
public TextureObject next;
public Bitmap bitmap;
int id;
int width;
int height;
// vertex offset from which this texture is referenced
// or store texture id with vertex?
short offset;
short vertices;
public short offset;
public short vertices;
TextureObject(int id) {
this.id = id;

View File

@@ -24,8 +24,11 @@ import org.oscim.renderer.layer.TextureLayer;
import org.oscim.utils.GlUtils;
import android.opengl.GLES20;
import android.util.Log;
public final class TextureRenderer {
public final static boolean debug = false;
private static int mTextureProgram;
private static int hTextureMVMatrix;
private static int hTextureProjMatrix;
@@ -35,7 +38,7 @@ public final class TextureRenderer {
private static int hTextureTexCoord;
private static int mIndicesVBO;
final static int INDICES_PER_SPRITE = 6;
public final static int INDICES_PER_SPRITE = 6;
final static int VERTICES_PER_SPRITE = 4;
final static int SHORTS_PER_VERTICE = 6;
// per texture
@@ -89,9 +92,9 @@ public final class TextureRenderer {
public static Layer draw(Layer layer, float scale, float[] projection,
float matrix[], int offset) {
GlUtils.checkGlError("draw texture0");
// GlUtils.checkGlError("draw texture >");
GLES20.glUseProgram(mTextureProgram);
GlUtils.checkGlError("draw texture1");
int va = hTextureTexCoord;
if (!GLRenderer.vertexArray[va]) {
@@ -106,39 +109,48 @@ public final class TextureRenderer {
}
TextureLayer tl = (TextureLayer) layer;
GlUtils.checkGlError("draw texture2.");
GLES20.glUniform1f(hTextureScale, scale);
if (tl.fixed)
GLES20.glUniform1f(hTextureScale, scale);
else
GLES20.glUniform1f(hTextureScale, 1);
GLES20.glUniform1f(hTextureScreenScale, 1f / GLRenderer.mWidth);
GLES20.glUniformMatrix4fv(hTextureProjMatrix, 1, false, projection, 0);
GLES20.glUniformMatrix4fv(hTextureMVMatrix, 1, false, matrix, 0);
GlUtils.checkGlError("draw texture2");
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesVBO);
GlUtils.checkGlError("draw texture3");
for (TextureObject to = tl.textures; to != null; to = to.next) {
if (TextureRenderer.debug)
Log.d("...", "draw texture: " + to.id + " " + to.offset + " " + to.vertices);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, to.id);
GlUtils.checkGlError("draw texture4");
int maxVertices = MAX_ITEMS * INDICES_PER_SPRITE;
GlUtils.checkGlError("draw texture5");
for (int i = 0; i < to.vertices; i += maxVertices) {
// to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8)
int off = (to.offset + i) * 8 + offset;
// to.offset * 24(shorts) * 2(short-bytes) / 6(indices)
GLES20.glVertexAttribPointer(hTextureVertex, 4,
GLES20.GL_SHORT, false, 12, to.offset * 8 + offset);
GlUtils.checkGlError("draw texture..");
GLES20.glVertexAttribPointer(hTextureVertex, 4,
GLES20.GL_SHORT, false, 12, off);
GLES20.glVertexAttribPointer(hTextureTexCoord, 2,
GLES20.GL_SHORT, false, 12, to.offset * 8 + offset + 8);
GlUtils.checkGlError("draw texture...");
GLES20.glVertexAttribPointer(hTextureTexCoord, 2,
GLES20.GL_SHORT, false, 12, off + 8);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, to.vertices,
GLES20.GL_UNSIGNED_SHORT, 0);
int numVertices = to.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);
GlUtils.checkGlError("draw texture");
// GlUtils.checkGlError("< draw texture");
return layer.next;
}

View File

@@ -308,7 +308,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
SymbolLayer sl = (SymbolLayer) mLayers.textureLayers;
SymbolItem it = new SymbolItem();
SymbolItem it = SymbolItem.get();
it.x = mPoiX;
it.y = mPoiY;
it.bitmap = bitmap;

View File

@@ -23,16 +23,13 @@ import org.oscim.core.Tile;
import org.oscim.generator.JobTile;
import org.oscim.renderer.layer.TextItem;
import org.oscim.renderer.layer.VertexPool;
import org.oscim.renderer.overlays.Overlay;
import org.oscim.view.MapView;
import org.oscim.view.MapViewPosition;
import android.util.FloatMath;
import android.util.Log;
// FIXME move GLSurfaceView in separate class
public class TileManager { // extends GLSurfaceView {
private final static String TAG = "TileManager";
public class TileManager {
static final String TAG = TileManager.class.getSimpleName();
private static final int MAX_TILES_IN_QUEUE = 40;
private static final int CACHE_THRESHOLD = 10;
@@ -45,17 +42,12 @@ public class TileManager { // extends GLSurfaceView {
// new jobs for the MapWorkers
private static ArrayList<JobTile> mJobList;
// all tiles currently referenced
// all tiles
private static ArrayList<MapTile> mTiles;
// tiles that have new data to upload, see passTile()
private static ArrayList<MapTile> mTilesLoaded;
private static ArrayList<Overlay> mOverlays;
// TODO current boundary tiles, values used to check if position has
// changed for updating current tile list
private static boolean mInitial;
// private static MapPosition mCurPosition, mDrawPosition;
@@ -67,8 +59,6 @@ public class TileManager { // extends GLSurfaceView {
private static float[] mTileCoords = new float[8];
// private static int[] mBoundaryTiles = new int[8];
static int mUpdateCnt;
static ReentrantLock tilelock = new ReentrantLock();
static Tiles mCurrentTiles;
@@ -123,10 +113,6 @@ public class TileManager { // extends GLSurfaceView {
}
};
// why not try a pattern every now and then?
// but should do the same for GLRenderer.
// findbugs found that volatile thingy, though this class
// is created before any other thread starts
private static volatile TileManager SINGLETON;
public static TileManager create(MapView mapView) {
@@ -147,27 +133,15 @@ public class TileManager { // extends GLSurfaceView {
}
private TileManager(MapView mapView) {
// super(context);
mMapView = mapView;
mMapViewPosition = mapView.getMapViewPosition();
// Log.d(TAG, "init GLSurfaceLayer");
// setEGLConfigChooser(new GlConfigChooser());
// setEGLContextClientVersion(2);
//
// // setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
// mRenderer = new GLRenderer(mMapView);
// setRenderer(mRenderer);
//
// // if (!debugFrameTime)
// setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
mJobList = new ArrayList<JobTile>();
mTiles = new ArrayList<MapTile>();
mTilesLoaded = new ArrayList<MapTile>(30);
mOverlays = new ArrayList<Overlay>(5);
// this is probably a good place to init these
VertexPool.init();
QuadTree.init();
@@ -191,6 +165,7 @@ public class TileManager { // extends GLSurfaceView {
if (mMapView == null)
return;
// FIXME too messy!
if (clear || mInitial) {
// make sure onDrawFrame is not running
GLRenderer.drawlock.lock();
@@ -209,10 +184,6 @@ public class TileManager { // extends GLSurfaceView {
QuadTree.init();
// TODO clear overlay items data
mOverlays.clear();
// mOverlays.add(new Overlay());
// set up TileData arrays that are passed to gl-thread
int num = mWidth;
if (mWidth < mHeight)
@@ -246,11 +217,13 @@ public class TileManager { // extends GLSurfaceView {
}
float s = Tile.TILE_SIZE;
// load some additional tiles more than currently visible
// load some tiles more than currently visible
// TODO limit how many more...
float scale = mapPosition.scale * 0.75f;
float px = (float) mapPosition.x;
float py = (float) mapPosition.y;
// TODO hint whether to prefetch parent / children
int zdir = 0;
for (int i = 0; i < 8; i += 2) {
@@ -258,9 +231,6 @@ public class TileManager { // extends GLSurfaceView {
coords[i + 1] = (py + coords[i + 1] / scale) / s;
}
// TODO all following should probably be done in an idler instead
// to drain queued events. need to check how android handles things.
boolean changed = updateVisibleList(mapPosition, zdir);
mMapView.render();
@@ -276,6 +246,8 @@ public class TileManager { // extends GLSurfaceView {
}
public static Tiles getActiveTiles(Tiles td) {
if (mCurrentTiles == null)
return td;
if (td != null && td.serial == mUpdateCnt)
return td;
@@ -409,58 +381,65 @@ public class TileManager { // extends GLSurfaceView {
tile = QuadTree.getTile(x, y, zoomLevel);
if (tile == null) {
tile = new MapTile(x, y, zoomLevel);
QuadTree.add(tile);
if (tile != null) {
if (!tile.isActive())
mJobList.add(tile);
mTiles.add(tile);
mJobList.add(tile);
tileCounter++;
} else if (!tile.isActive()) {
mJobList.add(tile);
return tile;
}
// mNewTiles.tiles[tiles++] = tile;
// if (fetchChildren) {
// byte z = (byte) (zoomLevel + 1);
// for (int i = 0; i < 4; i++) {
// int cx = (xx << 1) + (i % 2);
// int cy = (yy << 1) + (i >> 1);
//
// MapTile c = QuadTree.getTile(cx, cy, z);
//
// if (c == null) {
// c = new MapTile(cx, cy, z);
//
// QuadTree.add(c);
// mTiles.add(c);
// }
//
// if (!c.isActive()) {
// mJobList.add(c);
// }
// }
// }
tile = new MapTile(x, y, zoomLevel);
QuadTree.add(tile);
// if (fetchParent || (!fetchProxy && zdir > 0 && zoomLevel > 0)) {
mTiles.add(tile);
mJobList.add(tile);
tileCounter++;
// if (zdir > 0 && zoomLevel > 0) {
// // prefetch parent
// MapTile p = tile.rel.parent.tile;
//
// if (p == null) {
// p = new MapTile(x >> 1, y >> 1, (byte) (zoomLevel - 1));
//
// QuadTree.add(p);
// mTiles.add(p);
// mJobList.add(p);
//
// } else if (!p.isActive()) {
// if (!mJobList.contains(p))
// mJobList.add(p);
// }
// }
return tile;
// mNewTiles.tiles[tiles++] = tile;
// boolean fetchParent = false;
// boolean fetchProxy = false;
// boolean fetchChildren = false;
// if (fetchChildren) {
// byte z = (byte) (zoomLevel + 1);
// for (int i = 0; i < 4; i++) {
// int cx = (x << 1) + (i % 2);
// int cy = (y << 1) + (i >> 1);
//
// MapTile c = QuadTree.getTile(cx, cy, z);
//
// if (c == null) {
// c = new MapTile(cx, cy, z);
//
// QuadTree.add(c);
// mTiles.add(c);
// }
//
// if (!c.isActive()) {
// mJobList.add(c);
// }
// }
// }
//
// if (fetchParent || (!fetchProxy && zdir > 0 && zoomLevel > 0)) {
// if (zdir > 0 && zoomLevel > 0) {
// // prefetch parent
// MapTile p = tile.rel.parent.tile;
//
// if (p == null) {
// p = new MapTile(x >> 1, y >> 1, (byte) (zoomLevel - 1));
//
// QuadTree.add(p);
// mTiles.add(p);
// mJobList.add(p);
//
// } else if (!p.isActive()) {
// if (!mJobList.contains(p))
// mJobList.add(p);
// }
// }
// }
}
private static void clearTile(MapTile t) {
@@ -492,7 +471,7 @@ public class TileManager { // extends GLSurfaceView {
byte zoom = mapPosition.zoomLevel;
long x = (long) mapPosition.x;
long y = (long) mapPosition.y;
// long center = Tile.TILE_SIZE << (zoom - 1);
long center = Tile.TILE_SIZE << (zoom - 1);
int diff;
long dx, dy;
@@ -506,11 +485,10 @@ public class TileManager { // extends GLSurfaceView {
if (diff == 0) {
dx = (t.pixelX + h) - x;
dy = (t.pixelY + h) - y;
// t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy)) *
// 0.25f;
// dx %= center;
// dy %= center;
t.distance = FloatMath.sqrt((dx * dx + dy * dy)) * 0.25f;
dx %= center;
dy %= center;
t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy)) * 0.25f;
// t.distance = FloatMath.sqrt((dx * dx + dy * dy)) * 0.25f;
} else if (diff > 0) {
// tile zoom level is child of current
@@ -522,20 +500,19 @@ public class TileManager { // extends GLSurfaceView {
dx = ((t.pixelX + h) >> (diff >> 1)) - x;
dy = ((t.pixelY + h) >> (diff >> 1)) - y;
}
// dx %= center;
// dy %= center;
// t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy));
t.distance = FloatMath.sqrt((dx * dx + dy * dy));
dx %= center;
dy %= center;
t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy));
// t.distance = FloatMath.sqrt((dx * dx + dy * dy));
} else {
// tile zoom level is parent of current
dx = ((t.pixelX + h) << -diff) - x;
dy = ((t.pixelY + h) << -diff) - y;
// dx %= center;
// dy %= center;
// t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy)) *
// (-diff * 0.5f);
t.distance = FloatMath.sqrt((dx * dx + dy * dy)) * (-diff * 0.5f);
dx %= center;
dy %= center;
t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy)) * (-diff * 0.5f);
// t.distance = FloatMath.sqrt((dx * dx + dy * dy)) * (-diff * 0.5f);
}
}
}
@@ -565,10 +542,9 @@ public class TileManager { // extends GLSurfaceView {
for (int i = 1; i < remove; i++) {
MapTile t = mTiles.remove(size - i);
// synchronized (t) {
if (t.isLocked()) {
// dont remove tile used by GLRenderer
// dont remove tile used by GLRenderer, or somewhere else
Log.d(TAG, "X not removing " + t + " " + t.distance);
mTiles.add(t);
} else if (t.isLoading) {
@@ -585,7 +561,6 @@ public class TileManager { // extends GLSurfaceView {
} else {
clearTile(t);
}
// }
}
}
@@ -616,7 +591,7 @@ public class TileManager { // extends GLSurfaceView {
for (int i = 0, n = size - MAX_TILES_IN_QUEUE / 2; i < n; n--) {
MapTile t = mTilesLoaded.get(i);
// synchronized (t) {
if (t.isLocked()) {
// Log.d(TAG, "keep unused tile data: " + t + " " +
// t.isActive);
@@ -629,7 +604,6 @@ public class TileManager { // extends GLSurfaceView {
mTiles.remove(t);
clearTile(t);
}
// }
}
}
@@ -650,21 +624,22 @@ public class TileManager { // extends GLSurfaceView {
// return true;
// }
// synchronized (tile) {
if (tile.vbo == null) {
tile.vbo = BufferObject.get();
if (tile.vbo == null) {
Log.d(TAG, "no VBOs left for " + tile);
tile.isLoading = false;
return false;
}
} else
if (tile.vbo != null) {
// BAD Things(tm) happend...
Log.d(TAG, "tile loaded before " + tile);
return true;
}
tile.vbo = BufferObject.get();
if (tile.vbo == null) {
Log.d(TAG, "no VBOs left for " + tile);
tile.isLoading = false;
return true;
}
tile.newData = true;
tile.isLoading = false;
// }
mMapView.render();
@@ -685,23 +660,4 @@ public class TileManager { // extends GLSurfaceView {
if (mWidth > 0 && mHeight > 0)
mInitial = true;
}
// public void setRenderTheme(RenderTheme t) {
// if (mRenderer != null)
// mRenderer.setRenderTheme(t);
//
// }
// @Override
// protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//
// Log.d(TAG, "onSizeChanged" + w + " " + h);
// mWidth = w;
// mHeight = h;
//
// if (mWidth > 0 && mHeight > 0)
// mInitial = true;
//
// super.onSizeChanged(w, h, oldw, oldh);
// }
}

View File

@@ -35,6 +35,5 @@ public abstract class Layer {
VertexPoolItem pool;
protected VertexPoolItem curItem;
protected void clear() {
}
abstract protected void clear();
}

View File

@@ -118,6 +118,10 @@ public class Layers {
TextureLayer sl = (TextureLayer) l;
sl.compile(sbuf);
}
// FIXME
addLayerItems(sbuf, textureLayers, Layer.SYMBOL, 0);
}
private static void addLayerItems(ShortBuffer sbuf, Layer l, byte type, int pos) {
@@ -162,14 +166,22 @@ public class Layers {
layers = layers.next;
}
while (textureLayers != null) {
textureLayers.clear();
Layer l = textureLayers;
while (l != null) {
// TextureLayer sl = (TextureLayer) textureLayers;
// if (sl.textures != null)
// TextureObject.release(sl.textures);
l.clear();
textureLayers = textureLayers.next;
if (l.pool != null) {
VertexPool.release(l.pool);
l.pool = null;
l.curItem = null;
}
// if (l instanceof TextLayer)
// ((TextLayer) l).clear();
l = l.next;
}
textureLayers = null;
}
}

View File

@@ -49,11 +49,18 @@ public final class LineLayer extends Layer {
outlines = link;
}
/*
/**
* line extrusion is based on code from GLMap
* (https://github.com/olofsj/GLMap/) by olofsj
*
* @param points
* array of points as float x_n = i, y_n = i+1
* @param index
* array of line indices holding the length of the individual
* lines
* @param closed
* whether to connect start- and end-point
*/
public void addLine(float[] points, short[] index, boolean closed) {
float x, y, nextX, nextY, prevX, prevY;
float a, ux, uy, vx, vy, wx, wy;
@@ -83,7 +90,7 @@ public final class LineLayer extends Layer {
if (length < 0)
break;
// save some vertices
// Note: just a hack to save some vertices
if (rounded && i > 200)
rounded = false;
@@ -520,4 +527,8 @@ public final class LineLayer extends Layer {
si.used = opos;
curItem = si;
}
@Override
protected void clear() {
}
}

View File

@@ -87,4 +87,7 @@ public final class PolygonLayer extends Layer {
curItem = si;
}
@Override
protected void clear() {
}
}

View File

@@ -15,15 +15,55 @@
package org.oscim.renderer.layer;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
public class SymbolItem {
private static Object lock = new Object();
private static SymbolItem pool;
public static SymbolItem get() {
synchronized (lock) {
if (pool == null)
return new SymbolItem();
SymbolItem ti = pool;
pool = pool.next;
ti.next = null;
return ti;
}
}
public static void release(SymbolItem ti) {
if (ti == null)
return;
synchronized (lock) {
while (ti != null) {
SymbolItem next = ti.next;
ti.drawable = null;
ti.bitmap = null;
ti.next = pool;
pool = ti;
ti = next;
}
}
}
SymbolItem next;
public Bitmap bitmap;
public Drawable drawable;
public float x;
public float y;
public boolean billboard;
public int state;
// center, top, bottom, left, right, top-left...
byte placement;
// byte placement;
}

View File

@@ -20,34 +20,37 @@ import org.oscim.renderer.TextureObject;
import org.oscim.renderer.TextureRenderer;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.Log;
// TODO share one static texture for all poi map symabols
public final class SymbolLayer extends TextureLayer {
private static String TAG = SymbolLayer.class.getSimpleName();
private final static String TAG = SymbolLayer.class.getSimpleName();
private final static int TEXTURE_WIDTH = TextureObject.TEXTURE_WIDTH;
private final static int TEXTURE_HEIGHT = TextureObject.TEXTURE_HEIGHT;
private final static float SCALE = 8.0f;
private static short[] mVertices;
SymbolItem symbols;
private Canvas mCanvas;
private Rect mRect = new Rect();
public SymbolLayer() {
if (mVertices == null)
mVertices = new short[TextureRenderer.MAX_ITEMS * 24];
type = Layer.SYMBOL;
fixed = true;
mCanvas = new Canvas();
}
public void addSymbol(SymbolItem item) {
verticesCnt += 4;
SymbolItem it = symbols;
for (; it != null; it = it.next) {
for (SymbolItem it = symbols; it != null; it = it.next) {
if (it.bitmap == item.bitmap) {
// insert after same bitmap
item.next = it.next;
it.next = item;
return;
@@ -58,30 +61,77 @@ public final class SymbolLayer extends TextureLayer {
symbols = item;
}
public void addDrawable(Drawable drawable, int state, float x, float y) {
verticesCnt += 4;
SymbolItem item = SymbolItem.get();
item.drawable = drawable;
item.x = x;
item.y = y;
item.billboard = true;
item.state = state;
for (SymbolItem it = symbols; it != null; it = it.next) {
if (it.drawable == item.drawable && it.state == item.state) {
// insert after same drawable
item.next = it.next;
it.next = item;
return;
}
}
item.next = symbols;
symbols = item;
}
@Override
void compile(ShortBuffer sbuf) {
if (TextureRenderer.debug)
Log.d("...", "compile");
for (TextureObject to = textures; to != null; to = to.next)
TextureObject.uploadTexture(to);
}
private final static int LBIT_MASK = 0xfffffffe;
// TODO ... reuse texture when only symbol position changed
@Override
public void compile(ShortBuffer sbuf) {
public boolean prepare() {
short numIndices = 0;
short offsetIndices = 0;
short curIndices = 0;
int pos = 0;
short buf[] = mVertices;
int bufLen = buf.length;
curItem = VertexPool.get();
pool = curItem;
VertexPoolItem si = curItem;
int pos = si.used;
short buf[] = si.vertices;
int advanceY = 0;
float x = 0;
float y = 0;
Canvas canvas = TextureObject.getCanvas();
TextureObject to = TextureObject.get();
textures = to;
mCanvas.setBitmap(to.bitmap);
int maxIndices = TextureRenderer.MAX_ITEMS * TextureRenderer.INDICES_PER_SPRITE;
for (SymbolItem it = symbols; it != null;) {
float width, height;
// add bitmap
float width = it.bitmap.getWidth();
float height = it.bitmap.getHeight();
if (it.bitmap != null) {
// add bitmap
width = it.bitmap.getWidth();
height = it.bitmap.getHeight();
} else {
width = it.drawable.getIntrinsicWidth();
height = it.drawable.getIntrinsicHeight();
}
if (height > advanceY)
advanceY = (int) height;
@@ -91,43 +141,67 @@ public final class SymbolLayer extends TextureLayer {
y += advanceY;
advanceY = (int) (height + 0.5f);
if (y + height > TEXTURE_HEIGHT) {
Log.d(TAG, "reached max symbols");
TextureObject to = TextureObject.uploadCanvas(offsetIndices, numIndices);
offsetIndices = numIndices;
to.next = textures;
textures = to;
sbuf.put(buf, 0, pos);
pos = 0;
x = 0;
y = 0;
advanceY = (int) height;
}
}
canvas.drawBitmap(it.bitmap, x, y, null);
if (y + height > TEXTURE_HEIGHT || curIndices == maxIndices) {
Log.d(TAG, "reached max symbols: " + numIndices);
float hw = width / 2.0f;
float hh = height / 2.0f;
to.offset = offsetIndices;
to.vertices = curIndices;
short x1 = (short) (SCALE * (-hw));
short x2 = (short) (SCALE * (hw));
short y1 = (short) (SCALE * (hh));
short y2 = (short) (SCALE * (-hh));
numIndices += curIndices;
offsetIndices = numIndices;
curIndices = 0;
to.next = TextureObject.get();
to = to.next;
mCanvas.setBitmap(to.bitmap);
x = 0;
y = 0;
advanceY = (int) height;
}
if (it.bitmap != null) {
mCanvas.drawBitmap(it.bitmap, x, y, null);
} else {
it.drawable.copyBounds(mRect);
it.drawable.setBounds((int) x, (int) y, (int) (x + width), (int) (y + height));
it.drawable.draw(mCanvas);
it.drawable.setBounds(mRect);
}
short x1, y1, x2, y2;
if (it.bitmap != null) {
float hw = width / 2.0f;
float hh = height / 2.0f;
x1 = (short) (SCALE * (-hw));
x2 = (short) (SCALE * (hw));
y1 = (short) (SCALE * (hh));
y2 = (short) (SCALE * (-hh));
} else {
// use drawable offsets (for marker hotspot)
x2 = (short) (SCALE * (mRect.left));
y2 = (short) (SCALE * (mRect.top));
x1 = (short) (SCALE * (mRect.right));
y1 = (short) (SCALE * (mRect.bottom));
}
short u1 = (short) (SCALE * x);
short v1 = (short) (SCALE * y);
short u2 = (short) (SCALE * (x + width));
short v2 = (short) (SCALE * (y + height));
// add symbol items referencing the same bitmap
// add symbol items referencing the same bitmap / drawable
for (SymbolItem it2 = it;; it2 = it2.next) {
if (it2 == null || it2.bitmap != it.bitmap) {
if (it2 == null
// || (curIndices == maxIndices)
|| (it.drawable != null && it2.drawable != it.drawable)
|| (it.bitmap != null && it2.bitmap != it.bitmap)) {
it = it2;
break;
}
@@ -166,24 +240,41 @@ public final class SymbolLayer extends TextureLayer {
buf[pos++] = v1;
// six elements used to draw the four vertices
numIndices += 6;
curIndices += TextureRenderer.INDICES_PER_SPRITE;
if (pos == VertexPoolItem.SIZE) {
si.used = VertexPoolItem.SIZE;
si = si.next = VertexPool.get();
buf = si.vertices;
pos = 0;
}
// FIXME this does not work, need to draw bitmap on next
// texture...
if (pos == bufLen) {
sbuf.put(buf, 0, pos);
pos = 0;
}
// if (pos == bufLen) {
// sbuf.put(buf, 0, pos);
// pos = 0;
// }
x += width;
}
}
TextureObject to = TextureObject.uploadCanvas(offsetIndices, numIndices);
to.offset = offsetIndices;
to.vertices = curIndices;
to.next = textures;
textures = to;
si.used = pos;
curItem = si;
sbuf.put(buf, 0, pos);
return true;
}
@Override
protected void clear() {
TextureObject.release(textures);
SymbolItem.release(symbols);
textures = null;
symbols = null;
verticesCnt = 0;
}
}

View File

@@ -27,7 +27,9 @@ public class TextItem {
TextItem ti = pool;
pool = pool.next;
ti.next = null;
return ti;
}
}
@@ -73,5 +75,6 @@ public class TextItem {
public Text text;
public float width;
public short x1, y1, x2, y2;
// public byte placement
}

View File

@@ -25,26 +25,28 @@ import android.util.Log;
public final class TextLayer extends TextureLayer {
private static String TAG = TextureLayer.class.getSimpleName();
// private static String TAG = TextureLayer.class.getSimpleName();
private final static int TEXTURE_WIDTH = TextureObject.TEXTURE_WIDTH;
private final static int TEXTURE_HEIGHT = TextureObject.TEXTURE_HEIGHT;
private final static float SCALE = 8.0f;
private final static int LBIT_MASK = 0xfffffffe;
private static short[] mVertices;
private static int mFontPadX = 1;
private static int mFontPadY = 1;
TextItem labels;
private Canvas mCanvas;
public TextItem getLabels() {
return labels;
}
public TextLayer() {
if (mVertices == null)
mVertices = new short[TextureRenderer.MAX_ITEMS * 24];
type = Layer.SYMBOL;
mCanvas = new Canvas();
fixed = true;
}
public void addText(TextItem item) {
@@ -53,8 +55,10 @@ public final class TextLayer extends TextureLayer {
for (; it != null; it = it.next) {
if (it.text == item.text) {
// insert after text of same type
item.next = it.next;
it.next = item;
return;
}
}
@@ -64,24 +68,44 @@ public final class TextLayer extends TextureLayer {
}
@Override
public void compile(ShortBuffer sbuf) {
int numLabel = 0;
void compile(ShortBuffer sbuf) {
if (TextureRenderer.debug)
Log.d("...", "compile");
for (TextureObject to = textures; to != null; to = to.next)
TextureObject.uploadTexture(to);
}
@Override
public boolean prepare() {
if (TextureRenderer.debug)
Log.d("...", "prepare");
// int numLabel = 0;
// int numTextures = 0;
short numIndices = 0;
short offsetIndices = 0;
int pos = 0;
short buf[] = mVertices;
int bufLen = buf.length;
curItem = VertexPool.get();
pool = curItem;
VertexPoolItem si = curItem;
int pos = si.used;
short buf[] = si.vertices;
int advanceY = 0;
float x = 0;
float y = 0;
float yy;
Canvas canvas = TextureObject.getCanvas();
TextureObject to = TextureObject.get();
textures = to;
mCanvas.setBitmap(to.bitmap);
for (TextItem it = labels; it != null; it = it.next) {
numLabel++;
// numLabel++;
float width = it.width + 2 * mFontPadX;
float height = (int) (it.text.fontHeight) + 2 * mFontPadY + 0.5f;
@@ -99,33 +123,27 @@ public final class TextLayer extends TextureLayer {
// numLabel + " "
// + ((numIndices - offsetIndices) / 6));
// need to sync bitmap upload somehow???
TextureObject to = TextureObject.uploadCanvas(offsetIndices, numIndices);
to.offset = offsetIndices;
to.vertices = (short) (numIndices - offsetIndices);
offsetIndices = numIndices;
to.next = textures;
textures = to;
to.next = TextureObject.get();
to = to.next;
sbuf.put(buf, 0, pos);
pos = 0;
mCanvas.setBitmap(to.bitmap);
x = 0;
y = 0;
advanceY = (int) height;
// clear bitmap, TODO rotate two canvas to reduce the chance
// of having upload lock draing to the canvas?
canvas = TextureObject.getCanvas();
// numTextures++;
}
}
yy = y + (height - 1) - it.text.fontDescent - mFontPadY;
if (it.text.stroke != null)
canvas.drawText(it.string, x + it.width / 2, yy, it.text.stroke);
mCanvas.drawText(it.string, x + it.width / 2, yy, it.text.stroke);
canvas.drawText(it.string, x + it.width / 2, yy, it.text.paint);
mCanvas.drawText(it.string, x + it.width / 2, yy, it.text.paint);
// FIXME !!!
if (width > TEXTURE_WIDTH)
@@ -207,30 +225,41 @@ public final class TextLayer extends TextureLayer {
// six indices to draw the four vertices
numIndices += 6;
// FIXME this does not work, need to draw bitmap on next
// texture...
if (pos == bufLen) {
Log.d(TAG, "--- reached max label per texture " + numLabel);
sbuf.put(buf, 0, pos);
if (pos == VertexPoolItem.SIZE) {
si.used = VertexPoolItem.SIZE;
si = si.next = VertexPool.get();
buf = si.vertices;
pos = 0;
}
// FIXME this does not work, need to draw bitmap on next
// texture...
// if (numLabel == TextureRenderer.MAX_ITEMS) {
// Log.d(TAG, "--- reached max label per texture " + numLabel);
// sbuf.put(buf, 0, pos);
// pos = 0;
// }
x += width;
}
TextureObject to = TextureObject.uploadCanvas(offsetIndices, numIndices);
to.offset = offsetIndices;
to.vertices = (short) (numIndices - offsetIndices);
to.next = textures;
textures = to;
sbuf.put(buf, 0, pos);
si.used = pos;
curItem = si;
// Log.d(TAG, "added labels " + numTextures + " " + numLabel);
return true;
}
@Override
protected void clear() {
TextureObject.release(textures);
TextItem.release(labels);
textures = null;
labels = null;
verticesCnt = 0;
}
}

View File

@@ -20,12 +20,13 @@ import org.oscim.renderer.TextureObject;
public abstract class TextureLayer extends Layer {
public TextureObject textures;
public boolean fixed;
/**
* @param sbuf
* buffer to add vertices
*/
void compile(ShortBuffer sbuf) {
}
abstract void compile(ShortBuffer sbuf);
abstract public boolean prepare();
}

View File

@@ -15,15 +15,12 @@
package org.oscim.renderer.layer;
public class VertexPoolItem {
final short[] vertices;
final short[] vertices = new short[SIZE];
int used;
VertexPoolItem next;
VertexPoolItem() {
vertices = new short[SIZE];
used = 0;
}
// must be multiple of 4 (expected in LineLayer/PolygonLayer)
static final int SIZE = 256;
// and 24 (Texture Layer)
static final int SIZE = 360;
}

View File

@@ -14,6 +14,7 @@
*/
package org.oscim.renderer.overlays;
import org.oscim.core.MapPosition;
import org.oscim.core.Tile;
import org.oscim.renderer.layer.Layer;
import org.oscim.renderer.layer.LineLayer;
@@ -27,13 +28,13 @@ import android.graphics.Color;
import android.graphics.Paint.Cap;
import android.util.Log;
public class OverlayGrid extends Overlay {
public class OverlayGrid extends RenderOverlay {
private float[] mPoints;
private short[] mIndex;
private Text mText;
OverlayGrid(MapView mapView) {
public OverlayGrid(MapView mapView) {
super(mapView);
int size = Tile.TILE_SIZE;
@@ -91,6 +92,8 @@ public class OverlayGrid extends Overlay {
tl.addText(ti);
}
}
tl.prepare();
layers.textureLayers = tl;
}
@@ -107,7 +110,7 @@ public class OverlayGrid extends Overlay {
}
@Override
public synchronized void update(boolean positionChanged, boolean tilesChanged) {
public synchronized void update(MapPosition curPos, boolean positionChanged, boolean tilesChanged) {
updateMapPosition();
@@ -134,6 +137,8 @@ public class OverlayGrid extends Overlay {
ll.width = 1.5f;
ll.addLine(mPoints, mIndex, false);
Log.d("...", "update labels");
addLabels(x, y, mCurZ);
newData = true;

View File

@@ -14,16 +14,16 @@
*/
package org.oscim.renderer.overlays;
import org.oscim.renderer.layer.Layer;
import org.oscim.renderer.layer.LineLayer;
import java.io.IOException;
import org.oscim.core.MapPosition;
import org.oscim.renderer.layer.SymbolItem;
import org.oscim.renderer.layer.SymbolLayer;
import org.oscim.renderer.layer.TextItem;
import org.oscim.theme.renderinstruction.Line;
import org.oscim.theme.renderinstruction.BitmapUtils;
import org.oscim.view.MapView;
import android.graphics.Color;
import android.graphics.Paint.Cap;
public class OverlayTest extends Overlay {
public class OverlayTest extends RenderOverlay {
TextItem labels;
@@ -31,15 +31,16 @@ public class OverlayTest extends Overlay {
private boolean first = true;
OverlayTest(MapView mapView) {
public OverlayTest(MapView mapView) {
super(mapView);
LineLayer ll = (LineLayer) layers.getLayer(1, Layer.LINE);
ll.line = new Line(Color.BLUE, 1.0f, Cap.BUTT);
ll.width = 2;
float[] points = { -100, -100, 100, -100, 100, 100, -100, 100, -100, -100 };
short[] index = { (short) points.length };
ll.addLine(points, index, false);
// LineLayer ll = (LineLayer) layers.getLayer(1, Layer.LINE);
// ll.line = new Line(Color.BLUE, 1.0f, Cap.BUTT);
// ll.width = 2;
// float[] points = { -100, -100, 100, -100, 100, 100, -100, 100, -100, -100 };
// short[] index = { (short) points.length };
// ll.addLine(points, index, false);
//
// PolygonLayer pl = (PolygonLayer) layers.getLayer(0, Layer.POLYGON);
// pl.area = new Area(Color.argb(128, 255, 0, 0));
@@ -53,30 +54,33 @@ public class OverlayTest extends Overlay {
// short[] pindex = { (short) ppoints.length };
// pl.addPolygon(ppoints, pindex);
// SymbolLayer sl = new SymbolLayer();
// SymbolItem it = new SymbolItem();
//
// it.x = 0;
// it.y = 0;
// // billboard always faces camera
// it.billboard = true;
//
// try {
// it.bitmap = BitmapUtils.createBitmap("file:/sdcard/cheshire.png");
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// sl.addSymbol(it);
//
// SymbolItem it2 = new SymbolItem();
// it2.bitmap = it.bitmap;
// it2.x = 0;
// it2.y = 0;
// // billboard always faces camera
// it2.billboard = false;
//
// sl.addSymbol(it2);
SymbolLayer sl = new SymbolLayer();
SymbolItem it = new SymbolItem();
it.x = 0;
it.y = 0;
// billboard always faces camera
it.billboard = true;
try {
it.bitmap = BitmapUtils.createBitmap("file:/sdcard/cheshire.png");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sl.addSymbol(it);
SymbolItem it2 = new SymbolItem();
it2.bitmap = it.bitmap;
it2.x = 0;
it2.y = 0;
// billboard always faces camera
it2.billboard = false;
sl.addSymbol(it2);
sl.fixed = false;
layers.textureLayers = sl;
// TextLayer tl = new TextLayer();
// Text t = Text.createText(20, 2, Color.WHITE, Color.BLACK, false);
@@ -92,14 +96,16 @@ public class OverlayTest extends Overlay {
}
@Override
public synchronized void update(boolean positionChanged, boolean tilesChanged) {
public synchronized void update(MapPosition curPos, boolean positionChanged, boolean tilesChanged) {
// keep position constant (or update layer relative to new position)
mMapView.getMapViewPosition().getMapPosition(mMapPosition, null);
//mMapView.getMapViewPosition().getMapPosition(mMapPosition, null);
if (first) {
// fix at initial position
// mapView.getMapViewPosition().getMapPosition(mMapPosition, null);
updateMapPosition();
first = false;
((SymbolLayer) (layers.textureLayers)).prepare();
// pass layers to be uploaded and drawn to GL Thread
// afterwards never modify 'layers' outside of this function!

View File

@@ -17,8 +17,8 @@ package org.oscim.renderer.overlays;
import org.oscim.core.MapPosition;
import org.oscim.core.Tile;
import org.oscim.renderer.TileManager;
import org.oscim.renderer.MapTile;
import org.oscim.renderer.TileManager;
import org.oscim.renderer.Tiles;
import org.oscim.renderer.layer.TextItem;
import org.oscim.renderer.layer.TextLayer;
@@ -29,20 +29,23 @@ import org.oscim.view.MapView;
import android.os.SystemClock;
import android.util.FloatMath;
public class OverlayText extends Overlay {
public class OverlayText extends RenderOverlay {
private Tiles tiles;
private LabelThread mThread;
/* package */boolean mRun;
/* package */boolean mRerun;
private MapPosition mWorkPos;
private TextLayer mWorkLayer;
private TextLayer mNewLayer;
/* package */boolean mRun;
/* package */boolean mRerun;
class LabelThread extends PausableThread {
@Override
protected void doWork() {
SystemClock.sleep(250);
SystemClock.sleep(300);
mRun = false;
updateLabels();
mMapView.redrawMap();
@@ -70,14 +73,29 @@ public class OverlayText extends Overlay {
void updateLabels() {
tiles = TileManager.getActiveTiles(tiles);
// Log.d("...", "relabel " + mRerun + " " + x + " " + y);
if (tiles.cnt == 0)
return;
mMapView.getMapViewPosition().getMapPosition(mWorkPos, null);
// TODO tiles might be from another zoomlevel than the current:
TextLayer tl = mWorkLayer;
if (tl == null)
tl = new TextLayer();
// tiles might be from another zoomlevel than the current:
// this scales MapPosition to the zoomlevel of tiles...
// TODO create a helper function in MapPosition
int diff = tiles.tiles[0].zoomLevel - mWorkPos.zoomLevel;
if (diff > 1 || diff < -2) {
synchronized (this) {
mNewLayer = tl;
}
return;
}
float div = FastMath.pow(diff);
// fix map position to tile coordinates
@@ -89,14 +107,11 @@ public class OverlayText extends Overlay {
mWorkPos.zoomLevel += diff;
mWorkPos.scale = div;
// Log.d("...", "relabel " + mRerun + " " + x + " " + y);
TextLayer tl = new TextLayer();
float angle = (float) Math.toRadians(mWorkPos.angle);
float cos = FloatMath.cos(angle);
float sin = FloatMath.sin(angle);
// TODO more sophisticated placement :)
for (int i = 0, n = tiles.cnt; i < n; i++) {
MapTile t = tiles.tiles[i];
if (!t.isVisible)
@@ -104,7 +119,6 @@ public class OverlayText extends Overlay {
int dx = (t.tileX - x) * Tile.TILE_SIZE;
int dy = (t.tileY - y) * Tile.TILE_SIZE;
// Log.d("...", "update tiles " + dx + " " + dy);
for (TextItem ti = t.labels; ti != null; ti = ti.next) {
@@ -129,20 +143,27 @@ public class OverlayText extends Overlay {
}
}
// draw text to bitmaps and create vertices
tl.prepare();
// everything synchronized?
synchronized (this) {
mWorkLayer = tl;
mNewLayer = tl;
}
}
@Override
public synchronized void update(boolean positionChanged, boolean tilesChanged) {
public synchronized void update(MapPosition curPos, boolean positionChanged, boolean tilesChanged) {
// Log.d("...", "update " + tilesChanged + " " + positionChanged);
if (mWorkLayer != null) {
if (mNewLayer != null) {
// keep text layer, not recrating its canvas each time...
mWorkLayer = (TextLayer) layers.textureLayers;
layers.clear();
layers.textureLayers = mWorkLayer;
mWorkLayer = null;
layers.textureLayers = mNewLayer;
mNewLayer = null;
// make the 'labeled' MapPosition current
MapPosition tmp = mMapPosition;
@@ -154,7 +175,6 @@ public class OverlayText extends Overlay {
}
if (tilesChanged || positionChanged) {
if (!mRun) {
mRun = true;
synchronized (mThread) {

View File

@@ -28,12 +28,14 @@ import org.oscim.view.MapView;
import android.opengl.GLES20;
import android.opengl.Matrix;
import android.util.Log;
public abstract class Overlay {
public abstract class RenderOverlay {
protected final MapView mMapView;
// keep the Position for which the Overlay is rendered
protected MapPosition mMapPosition;
// current Layers to draw
public final Layers layers;
// flag to set when data is ready for (re)compilation.
@@ -44,19 +46,14 @@ public abstract class Overlay {
public BufferObject vbo;
public Overlay(MapView mapView) {
public RenderOverlay(MapView mapView) {
mMapView = mapView;
mMapPosition = new MapPosition();
layers = new Layers();
}
synchronized boolean onTouch(boolean down) {
Log.d("...", "Overlay handle onTouch " + down);
return true;
}
/**
* update mMapPosition
* Utility: update mMapPosition
*
* @return true if position has changed
*/
@@ -68,12 +65,13 @@ public abstract class Overlay {
// use synchronized (this){} when updating 'layers' from another thread
/**
* @param curPos TODO
* @param positionChanged
* true when MapPosition has changed
* @param tilesChanged
* true when loaded tiles changed
*/
public synchronized void update(boolean positionChanged, boolean tilesChanged) {
public synchronized void update(MapPosition curPos, boolean positionChanged, boolean tilesChanged) {
// // keep position constant (or update layer relative to new position)
// mMapView.getMapViewPosition().getMapPosition(mMapPosition, null);
//
@@ -110,23 +108,20 @@ public abstract class Overlay {
// float scale = curPos.scale / div;
for (Layer l = layers.textureLayers; l != null;) {
l = TextureRenderer.draw(l, (mMapPosition.scale / pos.scale) * div, proj, mv,
layers.texOffset);
}
}
private float setMatrix(MapPosition curPos, float[] matrix) {
// TODO if oPos == curPos this could be simplified
MapPosition oPos = mMapPosition;
byte z = oPos.zoomLevel;
// int diff = curPos.zoomLevel - z;
float div = FastMath.pow(z - curPos.zoomLevel);
// if (diff < 0)
// div = (1 << -diff);
// else if (diff > 0)
// div = (1.0f / (1 << diff));
float div = FastMath.pow(z - curPos.zoomLevel);
float x = (float) (oPos.x - curPos.x * div);
float y = (float) (oPos.y - curPos.y * div);
@@ -145,8 +140,8 @@ public abstract class Overlay {
matrix[12] = x * scale;
matrix[13] = y * scale;
// scale to current tile world coordinates
scale = (curPos.scale / oPos.scale) / div;
// scale to tile to world coordinates
scale /= GLRenderer.COORD_MULTIPLIER;
matrix[0] = scale;
matrix[5] = scale;