- started overlays

- started symbol layer
- move renderer and generator out of view package
  - hopefully the last big refactoring for a while...
- improve perspective, plane should be more far away to decrease foreshortening
This commit is contained in:
Hannes Janetzek 2012-10-09 13:23:15 +02:00
parent 2713f3bc6f
commit 33d8865d7b
128 changed files with 2360 additions and 1417 deletions

View File

@ -21,7 +21,7 @@
>
<!-- android:theme="@style/Theme.TileMap" -->
<activity
android:name="org.oscim.app.TileMap"
android:name="TileMap"
android:configChanges="orientation|screenSize" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -34,4 +34,4 @@
<activity android:name=".InfoView" />
</application>
</manifest>
</manifest>

View File

@ -15,4 +15,4 @@
# 'key.alias' for the name of the key to use.
# The password will be asked during the build when you use the 'release' target.
jar.libs.dir=lib
#jar.libs.dir=

View File

@ -15,7 +15,7 @@
package org.oscim.app;
import org.oscim.core.GeoPoint;
import org.oscim.view.MapPosition;
import org.oscim.core.MapPosition;
import android.content.Context;
import android.location.Criteria;

View File

@ -4,21 +4,18 @@ import java.io.FileFilter;
import java.io.FileNotFoundException;
import org.oscim.app.filefilter.FilterByFileExtension;
import org.oscim.app.filefilter.ValidMapFile;
import org.oscim.app.filefilter.ValidRenderTheme;
import org.oscim.app.filepicker.FilePicker;
import org.oscim.app.preferences.EditPreferences;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition;
import org.oscim.database.MapDatabases;
import org.oscim.theme.InternalRenderTheme;
import org.oscim.utils.AndroidUtils;
import org.oscim.view.DebugSettings;
import org.oscim.view.MapActivity;
import org.oscim.view.MapPosition;
import org.oscim.view.MapView;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
@ -59,11 +56,11 @@ public class TileMap extends MapActivity {
private static final int DIALOG_ENTER_COORDINATES = 0;
private static final int DIALOG_INFO_MAP_FILE = 1;
private static final int DIALOG_LOCATION_PROVIDER_DISABLED = 2;
private static final FileFilter FILE_FILTER_EXTENSION_MAP =
new FilterByFileExtension(".map");
// private static final FileFilter FILE_FILTER_EXTENSION_MAP =
// new FilterByFileExtension(".map");
private static final FileFilter FILE_FILTER_EXTENSION_XML =
new FilterByFileExtension(".xml");
private static final int SELECT_MAP_FILE = 0;
// private static final int SELECT_MAP_FILE = 0;
private static final int SELECT_RENDER_THEME_FILE = 1;
LocationHandler mLocation;
@ -232,11 +229,12 @@ public class TileMap extends MapActivity {
return mMapView.onTrackballEvent(event);
}
private void startMapFilePicker() {
FilePicker.setFileDisplayFilter(FILE_FILTER_EXTENSION_MAP);
FilePicker.setFileSelectFilter(new ValidMapFile());
startActivityForResult(new Intent(this, FilePicker.class), SELECT_MAP_FILE);
}
// private void startMapFilePicker() {
// FilePicker.setFileDisplayFilter(FILE_FILTER_EXTENSION_MAP);
// FilePicker.setFileSelectFilter(new ValidMapFile());
// startActivityForResult(new Intent(this, FilePicker.class),
// SELECT_MAP_FILE);
// }
private void startRenderThemePicker() {
FilePicker.setFileDisplayFilter(FILE_FILTER_EXTENSION_XML);
@ -598,12 +596,12 @@ public class TileMap extends MapActivity {
// }
}
static class VersionHelper {
@TargetApi(11)
static void refreshActionBarMenu(Activity activity) {
activity.invalidateOptionsMenu();
}
}
// static class VersionHelper {
// @TargetApi(11)
// static void refreshActionBarMenu(Activity activity) {
// activity.invalidateOptionsMenu();
// }
// }
@Override
protected void onSaveInstanceState(Bundle outState) {

View File

@ -12,10 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view;
import org.oscim.core.GeoPoint;
import org.oscim.core.MercatorProjection;
package org.oscim.core;
import android.opengl.Matrix;
@ -30,11 +27,13 @@ public class MapPosition {
public byte zoomLevel;
public float scale;
public float angle;
public float tilt;
public double x;
public double y;
public float[] rotation;
public float[] viewMatrix;
public float[] rotateMatrix;
public MapPosition() {
this.zoomLevel = (byte) 1;
@ -46,9 +45,13 @@ public class MapPosition {
this.y = MercatorProjection.latitudeToPixelY(this.lat, zoomLevel);
}
// FIXME remove this here
public void init() {
rotation = new float[16];
Matrix.setIdentityM(rotation, 0);
viewMatrix = new float[16];
Matrix.setIdentityM(viewMatrix, 0);
rotateMatrix = new float[16];
Matrix.setIdentityM(rotateMatrix, 0);
}
/**
@ -60,7 +63,6 @@ public class MapPosition {
* ...
*/
public MapPosition(GeoPoint geoPoint, byte zoomLevel, float scale) {
// this.geoPoint = geoPoint;
this.zoomLevel = zoomLevel;
this.scale = scale;
this.lat = geoPoint.getLatitude();
@ -84,10 +86,10 @@ public class MapPosition {
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("MapPosition [geoPoint=");
builder.append("lat");
builder.append("MapPosition [");
builder.append("lat=");
builder.append(this.lat);
builder.append("lon");
builder.append(", lon=");
builder.append(this.lon);
builder.append(", zoomLevel=");
builder.append(this.zoomLevel);

View File

@ -14,7 +14,6 @@
*/
package org.oscim.core;
import org.oscim.view.MapPosition;
/**
* An implementation of the spherical Mercator projection.

View File

@ -24,7 +24,8 @@ public class WebMercator {
*/
public static final String NAME = "SphericalMercator";
private static final double f900913 = 20037508.342789244;
// earth radius * pi, roughly
public static final double f900913 = 20037508.342789244;
private static final double f900913_2 = 20037508.342789244 * 2;
/**

View File

@ -16,7 +16,7 @@ package org.oscim.database;
import java.util.Map;
import org.oscim.view.generator.JobTile;
import org.oscim.generator.JobTile;
/**
*

View File

@ -30,7 +30,7 @@ import org.oscim.database.QueryResult;
import org.oscim.database.mapfile.header.MapFileHeader;
import org.oscim.database.mapfile.header.MapFileInfo;
import org.oscim.database.mapfile.header.SubFileParameter;
import org.oscim.view.generator.JobTile;
import org.oscim.generator.JobTile;
import android.os.Environment;
@ -819,7 +819,7 @@ public class MapDatabase implements IMapDatabase {
Tag[] wayTags = sMapFileHeader.getMapFileInfo().wayTags;
int[] textPos = new int[3];
// float[] labelPosition;
boolean skippedWays = false;
// boolean skippedWays = false;
int wayDataBlocks;
// skip string block
@ -858,7 +858,7 @@ public class MapDatabase implements IMapDatabase {
if (tags == null)
return false;
skippedWays = true;
// skippedWays = true;
mReadBuffer.setBufferPosition(pos);
}
@ -885,12 +885,12 @@ public class MapDatabase implements IMapDatabase {
// bit 5-8 represent the number of tag IDs
byte numberOfTags = (byte) (specialByte & WAY_NUMBER_OF_TAGS_BITMASK);
boolean changed = skippedWays;
skippedWays = false;
// boolean changed = skippedWays;
// skippedWays = false;
if (numberOfTags != 0) {
tags = mReadBuffer.readTags(wayTags, numberOfTags);
changed = true;
// changed = true;
}
if (tags == null)
return false;
@ -904,8 +904,8 @@ public class MapDatabase implements IMapDatabase {
// check if the way has a name
if ((featureByte & WAY_FEATURE_NAME) != 0) {
textPos[0] = mReadBuffer.readUnsignedInt();
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset
+ textPos[0]);
// String str =
mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos[0]);
// if (changed) {
// Tag[] tmp = tags;
// tags = new Tag[tmp.length + 1];

View File

@ -39,7 +39,7 @@ import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.MapInfo;
import org.oscim.database.OpenResult;
import org.oscim.database.QueryResult;
import org.oscim.view.generator.JobTile;
import org.oscim.generator.JobTile;
import android.os.Environment;
import android.os.SystemClock;
@ -65,8 +65,8 @@ public class MapDatabase implements IMapDatabase {
private static final String CACHE_FILE = "%d-%d-%d.tile";
private static final String SERVER_ADDR = "city.informatik.uni-bremen.de";
// private static final String URL = "/osci/map-live/";
private static final String URL = "/osci/oscim/";
private static final String URL = "/osci/map-live/";
// private static final String URL = "/osci/oscim/";
private final static float REF_TILE_SIZE = 4096.0f;

View File

@ -62,7 +62,7 @@ import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.MapInfo;
import org.oscim.database.OpenResult;
import org.oscim.database.QueryResult;
import org.oscim.view.generator.JobTile;
import org.oscim.generator.JobTile;
import android.os.Environment;
import android.os.SystemClock;

View File

@ -33,7 +33,7 @@ import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.MapInfo;
import org.oscim.database.OpenResult;
import org.oscim.database.QueryResult;
import org.oscim.view.generator.JobTile;
import org.oscim.generator.JobTile;
import org.postgresql.PGConnection;
import android.util.Log;

View File

@ -24,7 +24,7 @@ import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.MapInfo;
import org.oscim.database.OpenResult;
import org.oscim.database.QueryResult;
import org.oscim.view.generator.JobTile;
import org.oscim.generator.JobTile;
/**
*
@ -40,7 +40,7 @@ public class MapDatabase implements IMapDatabase {
private Tag[] mTags = { new Tag("natural", "water") };
private Tag[] mTagsWay = { new Tag("highway", "primary"), new Tag("name", "Highway Rd") };
private Tag[] mNameTags;
// private Tag[] mNameTags;
private final MapInfo mMapInfo =
new MapInfo(new BoundingBox(-180, -90, 180, 90),

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.generator;
package org.oscim.generator;
//import static org.oscim.view.mapgenerator.JobTile.LOADING;

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.generator;
package org.oscim.generator;
import org.oscim.core.Tile;

View File

@ -12,11 +12,11 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.generator;
package org.oscim.generator;
import org.oscim.renderer.MapRenderer;
import org.oscim.renderer.TileGenerator;
import org.oscim.utils.PausableThread;
import org.oscim.view.renderer.MapRenderer;
import org.oscim.view.renderer.TileGenerator;
/**
* A MapWorker uses a {@link TileGenerator} to generate map tiles. It runs in a

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.generator;
package org.oscim.generator;
import java.util.Comparator;

View File

@ -0,0 +1,118 @@
/*
* Copyright 2012 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General 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 License for more details.
*
* You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.renderer;
import android.opengl.GLES20;
class BufferObject {
private static BufferObject pool;
static synchronized BufferObject get() {
BufferObject bo;
if (pool == null) {
return null;
}
bo = pool;
pool = pool.next;
bo.next = null;
return bo;
}
// static synchronized BufferObject get(int size) {
// BufferObject bo, prev = null;
//
// if (pool == null) {
// return null;
// }
//
// int max = size * 4;
//
// for (bo = pool; bo != null; bo = bo.next) {
// if (bo.size > size && size < max)
// break;
//
// prev = bo;
// }
//
// if (prev != null && bo != null) {
// prev.next = bo.next;
// bo.next = null;
// return bo;
// }
//
// bo = pool;
// pool = pool.next;
// bo.next = null;
// return bo;
// }
static synchronized void release(BufferObject bo) {
bo.next = pool;
pool = bo;
}
// Note: only call from GL-Thread
static synchronized int limitUsage(int reduce) {
int vboIds[] = new int[10];
BufferObject[] tmp = new BufferObject[10];
int removed = 0;
int freed = 0;
for (BufferObject bo = pool; bo != null; bo = bo.next) {
if (bo.size > 0) {
freed += bo.size;
bo.size = 0;
vboIds[removed] = bo.id;
tmp[removed++] = bo;
if (removed == 10 || reduce < freed)
break;
}
}
if (removed > 0) {
GLES20.glDeleteBuffers(removed, vboIds, 0);
GLES20.glGenBuffers(removed, vboIds, 0);
for (int i = 0; i < removed; i++)
tmp[i].id = vboIds[i];
}
return freed;
}
static void init(int num) {
int[] mVboIds = new int[num];
GLES20.glGenBuffers(num, mVboIds, 0);
BufferObject bo;
for (int i = 1; i < num; i++) {
bo = new BufferObject(mVboIds[i]);
bo.next = pool;
pool = bo;
}
}
int id;
int size;
BufferObject next;
BufferObject(int id) {
this.id = id;
}
}

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer;
import static android.opengl.GLES20.GL_ARRAY_BUFFER;
import static android.opengl.GLES20.GL_BLEND;
@ -31,13 +31,14 @@ import java.util.concurrent.locks.ReentrantLock;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import org.oscim.core.MapPosition;
import org.oscim.core.Tile;
import org.oscim.renderer.MapRenderer.TilesData;
import org.oscim.renderer.layer.Layer;
import org.oscim.renderer.layer.Layers;
import org.oscim.theme.RenderTheme;
import org.oscim.utils.GlUtils;
import org.oscim.view.MapPosition;
import org.oscim.view.MapView;
import org.oscim.view.MapViewPosition;
import org.oscim.view.renderer.MapRenderer.TilesData;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
@ -55,7 +56,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private static final int CACHE_TILES_MAX = 250;
private static final int LIMIT_BUFFERS = 16 * MB;
static final float COORD_MULTIPLIER = 8.0f;
public static final float COORD_MULTIPLIER = 8.0f;
static int CACHE_TILES = CACHE_TILES_MAX;
@ -64,9 +65,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private static MapPosition mMapPosition;
private static ArrayList<VertexBufferObject> mVBOs;
// private static ArrayList<BufferObject> mVBOs;
private static int mWidth, mHeight;
static int mWidth, mHeight;
private static int rotateBuffers = 2;
private static ShortBuffer shortBuffer[];
@ -77,7 +78,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private static float[] mMVPMatrix = new float[16];
private static float[] mProjMatrix = new float[16];
private static float[] mTmpMatrix = new float[16];
private static float[] mTileCoords = new float[8];
private static float[] mDebugCoords = new float[8];
// mNextTiles is set by TileLoader and swapped with
// mDrawTiles in onDrawFrame in GL thread.
@ -99,8 +102,22 @@ public class GLRenderer implements GLSurfaceView.Renderer {
static ReentrantLock tilelock = new ReentrantLock();
static ReentrantLock drawlock = new ReentrantLock();
// Add additional tiles that serve as placeholer when flipping
// over date-line.
// I dont really like this but cannot think of a better solution:
// the other option would be to run scanbox each time for upload,
// drawing, proxies and text layer. needing to add placeholder only
// happens rarely, unless you live on Fidschi
/* package */static int mHolderCount;
static boolean[] vertexArray = { false, false };
// TODO
final class GLState {
boolean blend = false;
boolean depth = false;
}
// scanline fill class used to check tile visibility
private static ScanBox mScanBox = new ScanBox() {
@Override
@ -120,33 +137,35 @@ public class GLRenderer implements GLSurfaceView.Renderer {
return;
// add placeholder tiles to show both sides
// of date line...
// of date line. a little too complicated...
for (int x = x1; x < x2; x++) {
MapTile holder = null;
MapTile tile = null;
boolean found = false;
int xx = x;
if (x >= 0 && x < xmax)
continue;
int xx = x;
if (x < 0)
xx = xmax + x;
else
xx = x - xmax;
if (xx < 0 || xx >= xmax)
if (xx < 0 || xx >= xmax) {
// Log.d(TAG, "out of bounds " + y + " " + x + "/" + xx);
continue;
}
for (int i = cnt; i < cnt + mHolderCount; i++)
if (tiles[i].tileX == x && tiles[i].tileY == y) {
found = true;
break;
}
if (found)
if (found) {
// Log.d(TAG, "already added " + y + " " + x + "/" + xx);
continue;
}
for (int i = 0; i < cnt; i++)
if (tiles[i].tileX == xx && tiles[i].tileY == y) {
@ -154,11 +173,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
break;
}
if (tile == null)
if (tile == null) {
// Log.d(TAG, "not found " + y + " " + x + "/" + xx);
continue;
// Log.d(TAG, "add placeholder " + y + " " + x + ">>" + xx + " "
// + tile);
}
holder = new MapTile(x, y, mZoom);
holder.isVisible = true;
@ -173,7 +191,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
* the MapView
*/
public GLRenderer(MapView mapView) {
Log.d(TAG, "init MapRenderer");
mMapView = mapView;
mMapViewPosition = mapView.getMapViewPosition();
@ -208,14 +225,18 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mUpdateTiles = false;
}
private static ArrayList<Overlay> mOverlays;
/**
* Called by TileLoader when list of active tiles changed. the list is
* copied to mNextTiles to be used in next call to onDrawFrame
*
* @param tiles
* active tiles
* @param overlays
* ...
*/
static void updateTiles(TilesData tiles) {
static void updateTiles(TilesData tiles, ArrayList<Overlay> overlays) {
MapTile[] newTiles = tiles.tiles;
@ -223,6 +244,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
for (int i = 0, n = tiles.cnt; i < n; i++)
newTiles[i].lock();
mOverlays = overlays;
// dont flip next/drawTiles while copying
GLRenderer.tilelock.lock();
@ -243,28 +266,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
GLRenderer.tilelock.unlock();
}
/**
* called by TileLoader. when tile is removed from cache reuse its vbo.
*
* @param vbo
* the VBO
*/
static void addVBO(VertexBufferObject vbo) {
synchronized (mVBOs) {
mVBOs.add(vbo);
}
}
void setVBO(MapTile tile) {
synchronized (mVBOs) {
int numVBOs = mVBOs.size();
if (numVBOs > 0 && tile.vbo == null) {
tile.vbo = mVBOs.remove(numVBOs - 1);
}
}
}
void setRenderTheme(RenderTheme t) {
int bg = t.getMapBackground();
float[] c = new float[4];
@ -276,161 +277,121 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mUpdateColor = true;
}
private int uploadCnt = 0;
private static int uploadCnt = 0;
private boolean uploadTileData(MapTile tile) {
// Upload line data to vertex buffer object
// Log.d(TAG, "uploadTileData, " + tile);
private static boolean uploadLayers(Layers layers, BufferObject vbo, boolean addFill) {
int lineSize = LineRenderer.sizeOf(tile.lineLayers);
int polySize = PolygonRenderer.sizeOf(tile.polygonLayers);
int newSize = lineSize + polySize;
if (newSize == 0) {
LineRenderer.clear(tile.lineLayers);
PolygonRenderer.clear(tile.polygonLayers);
tile.lineLayers = null;
tile.polygonLayers = null;
tile.newData = false;
int newSize = layers.getSize();
if (newSize == 0)
return false;
}
GLES20.glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id);
GLES20.glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
// use multiple buffers to avoid overwriting buffer while current
// data is uploaded (or rather the blocking which is probably done to
// avoid overwriting)
if (uploadCnt >= rotateBuffers) {
uploadCnt = 0;
// GLES20.glFlush();
}
ShortBuffer sbuf = shortBuffer[uploadCnt];
// add fill coordinates
newSize += 8;
if (addFill)
newSize += 8;
// probably not a good idea to do this in gl thread...
if (sbuf.capacity() < newSize) {
ByteBuffer bbuf = ByteBuffer.allocateDirect(newSize * SHORT_BYTES)
.order(ByteOrder.nativeOrder());
sbuf = bbuf.asShortBuffer();
sbuf = ByteBuffer
.allocateDirect(newSize * SHORT_BYTES)
.order(ByteOrder.nativeOrder())
.asShortBuffer();
shortBuffer[uploadCnt] = sbuf;
sbuf.put(mFillCoords, 0, 8);
if (addFill)
sbuf.put(mFillCoords, 0, 8);
} else {
sbuf.clear();
if (addFill)
sbuf.put(mFillCoords, 0, 8);
// if (addFill)
// sbuf.position(8);
}
sbuf.clear();
sbuf.position(8);
PolygonRenderer.compileLayerData(tile.polygonLayers, sbuf);
tile.lineOffset = (8 + polySize);
if (tile.lineOffset != sbuf.position())
Log.d(TAG, "tiles lineoffset is wrong: " + tile + " "
+ tile.lineOffset + " "
+ sbuf.position() + " "
+ sbuf.limit() + " "
+ sbuf.remaining() + " "
+ PolygonRenderer.sizeOf(tile.polygonLayers) + " "
+ tile.rel);
tile.lineOffset *= SHORT_BYTES;
LineRenderer.compileLayerData(tile.lineLayers, sbuf);
layers.compile(sbuf, addFill);
sbuf.flip();
if (newSize != sbuf.remaining()) {
Log.d(TAG, "tiles wrong: " + tile + " "
Log.d(TAG, "wrong size: "
+ newSize + " "
+ sbuf.position() + " "
+ sbuf.limit() + " "
+ sbuf.remaining() + " "
+ LineRenderer.sizeOf(tile.lineLayers)
+ tile.isLoading + " "
+ tile.rel);
+ sbuf.remaining());
tile.newData = false;
// tile.newData = false;
return false;
}
newSize *= SHORT_BYTES;
// reuse memory allocated for vbo when possible and allocated
// memory is less then four times the new data
if (tile.vbo.size > newSize && tile.vbo.size < newSize * 4
if (vbo.size > newSize && vbo.size < newSize * 4
&& mBufferMemoryUsage < LIMIT_BUFFERS) {
GLES20.glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, sbuf);
} else {
mBufferMemoryUsage -= tile.vbo.size;
tile.vbo.size = newSize;
GLES20.glBufferData(GL_ARRAY_BUFFER, tile.vbo.size, sbuf, GL_DYNAMIC_DRAW);
mBufferMemoryUsage += tile.vbo.size;
mBufferMemoryUsage -= vbo.size;
vbo.size = newSize;
GLES20.glBufferData(GL_ARRAY_BUFFER, vbo.size, sbuf, GL_DYNAMIC_DRAW);
mBufferMemoryUsage += vbo.size;
}
uploadCnt++;
tile.isReady = true;
tile.newData = false;
return true;
}
private static boolean uploadTileData(MapTile tile) {
if (uploadLayers(tile.layers, tile.vbo, true))
tile.isReady = true;
tile.newData = false;
return tile.isReady;
}
private static boolean uploadOverlayData(Overlay overlay) {
if (uploadLayers(overlay.layers, overlay.vbo, true))
overlay.isReady = true;
overlay.newData = false;
return overlay.isReady;
}
private static void checkBufferUsage() {
// try to clear some unused vbo when exceding limit
if (mBufferMemoryUsage < LIMIT_BUFFERS) {
if (CACHE_TILES < CACHE_TILES_MAX)
CACHE_TILES += 50;
return;
}
// try to clear some unused vbo when exceding limit
Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / MB + "MB");
int vboIds[] = new int[10];
VertexBufferObject[] tmp = new VertexBufferObject[10];
mBufferMemoryUsage -= BufferObject.limitUsage(2 * MB);
int removed = 0;
synchronized (mVBOs) {
for (VertexBufferObject vbo : mVBOs) {
if (vbo.size == 0)
continue;
mBufferMemoryUsage -= vbo.size;
vbo.size = 0;
// this should free allocated memory but it does not.
// on HTC it causes OOM exception?!
// glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
// glBufferData(GL_ARRAY_BUFFER, 0, null,
// GLES20.GL_STATIC_DRAW);
// recreate vbo instead
vboIds[removed] = vbo.id;
tmp[removed++] = vbo;
if (removed == 10)
break;
}
}
if (removed > 0) {
GLES20.glDeleteBuffers(removed, vboIds, 0);
GLES20.glGenBuffers(removed, vboIds, 0);
for (int i = 0; i < removed; i++)
tmp[i].id = vboIds[i];
Log.d(TAG, "now: " + mBufferMemoryUsage / MB + "MB");
}
Log.d(TAG, "now: " + mBufferMemoryUsage / MB + "MB");
if (mBufferMemoryUsage > LIMIT_BUFFERS && CACHE_TILES > 100)
CACHE_TILES -= 50;
}
private static boolean mRotate = false;
private static void setMatrix(float[] matrix, MapTile tile,
float div, boolean project) {
MapPosition mapPosition = mMapPosition;
float x = (float) (tile.pixelX - mapPosition.x * div);
@ -448,12 +409,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
matrix[0] = scale;
matrix[5] = scale;
if (mRotate)
Matrix.multiplyMM(matrix, 0, mapPosition.rotation, 0, matrix, 0);
Matrix.multiplyMM(matrix, 0, mapPosition.viewMatrix, 0, matrix, 0);
if (project)
Matrix.multiplyMM(matrix, 0, mProjMatrix, 0, matrix, 0);
}
private static float scaleDiv(MapTile t) {
@ -492,14 +451,18 @@ public class GLRenderer implements GLSurfaceView.Renderer {
| GLES20.GL_DEPTH_BUFFER_BIT
| GLES20.GL_STENCIL_BUFFER_BIT);
// get current tiles to draw
if (mUpdateTiles) {
// get current tiles to draw
GLRenderer.tilelock.lock();
mUpdateTiles = false;
TilesData tmp = mDrawTiles;
mDrawTiles = mNextTiles;
mNextTiles = tmp;
mUpdateTiles = false;
GLRenderer.tilelock.unlock();
// force update of mapPosition
mMapPosition.zoomLevel = -1;
}
if (mDrawTiles == null || mDrawTiles.cnt == 0) {
@ -507,14 +470,16 @@ public class GLRenderer implements GLSurfaceView.Renderer {
return;
}
mRotate = mMapView.enableRotation || mMapView.enableCompass;
// get current MapPosition, set mTileCoords (mapping of screen to model
// coordinates)
MapPosition mapPosition = mMapPosition;
float[] coords = mTileCoords;
boolean changed = mMapViewPosition.getMapPosition(mapPosition, coords);
for (Overlay overlay : mOverlays) {
overlay.update(mMapView);
}
int tileCnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles;
@ -539,25 +504,12 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mHolderCount = 0;
mScanBox.scan(coords, tiles[0].zoomLevel);
tileCnt += mHolderCount;
// // TODO get the right function: trying to accomodate for the
// y-stretching introduced by the perspective transformation...
// float sw, sh;
// sw = MapViewPosition.VIEW_SCALE;
// sh = MapViewPosition.VIEW_SCALE;
// sh += (mMapViewPosition.mTilt / 150);
//
// Matrix.frustumM(mProjMatrix, 0, -sw * mWidth, sw * mWidth,
// sh * mHeight, -sh * mHeight, 1, 2);
//
// Matrix.translateM(mProjMatrix, 0, 0, 0,
// -MapViewPosition.VIEW_DISTANCE);
//
// mProjMatrix[10] = 0;
// mProjMatrix[14] = 0;
}
tileCnt += mHolderCount;
// Log.d(TAG, "visible: " + tileCnt);
uploadCnt = 0;
int updateTextures = 0;
@ -579,25 +531,30 @@ public class GLRenderer implements GLSurfaceView.Renderer {
uploadTileData(tile);
continue;
}
if (tile.holder != null) {
if (tile.holder.newData) {
uploadTileData(tile.holder);
}
tile.isReady = tile.holder.isReady;
} else if (!tile.isReady) {
// check near relatives if they can serve as proxy
MapTile rel = tile.rel.parent.tile;
if (rel != null && rel.newData) {
uploadTileData(rel);
} else {
for (int c = 0; c < 4; c++) {
if (tile.rel.child[c] == null)
continue;
rel = tile.rel.child[c].tile;
if (rel != null && rel.newData)
uploadTileData(rel);
}
if (tile.holder != null) {
// load tile that is referenced by this holder
if (tile.holder.newData)
uploadTileData(tile.holder);
tile.isReady = tile.holder.isReady;
} else if (!tile.isReady) {
// check near relatives than can serve as proxy
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
MapTile rel = tile.rel.parent.tile;
if (rel.newData)
uploadTileData(rel);
continue;
}
for (int c = 0; c < 4; c++) {
if ((tile.proxies & 1 << c) == 0)
continue;
MapTile rel = tile.rel.child[c].tile;
if (rel != null && rel.newData)
uploadTileData(rel);
}
}
}
@ -620,7 +577,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
}
// proxies are clipped to the region where nothing was drawn to depth
// buffer. TODO draw all parent before grandparent
// buffer.
// TODO draw all parent before grandparent
// TODO draw proxies for placeholder...
for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i];
if (t.isVisible && !t.isReady && (t.holder == null))
@ -639,7 +598,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
int z = mapPosition.zoomLevel;
float s = mapPosition.scale;
int zoomLevelDiff = Math.max(z - TileGenerator.STROKE_MAX_ZOOM_LEVEL, 0);
int zoomLevelDiff = Math.max(z - TileGenerator.STROKE_MAX_ZOOM_LEVEL,
0);
float scale = (float) Math.pow(1.4, zoomLevelDiff);
if (scale < 1)
scale = 1;
@ -647,7 +607,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (z >= TileGenerator.STROKE_MAX_ZOOM_LEVEL)
TextRenderer.beginDraw(scale / FloatMath.sqrt(s), mProjMatrix);
else
TextRenderer.beginDraw(1 / s, mProjMatrix);
TextRenderer.beginDraw(1f / s, mProjMatrix);
for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i];
@ -669,12 +629,53 @@ public class GLRenderer implements GLSurfaceView.Renderer {
TextRenderer.endDraw();
}
// TODO call overlay renderer here
// call overlay renderer
for (Overlay overlay : mOverlays) {
if (overlay.newData) {
if (overlay.vbo == null)
overlay.vbo = BufferObject.get();
if (overlay.vbo == null)
continue;
if (uploadOverlayData(overlay))
overlay.isReady = true;
}
if (!overlay.isReady)
continue;
// setMatrix(mMVPMatrix, overlay);
overlay.render(mMapPosition, mMVPMatrix, mProjMatrix);
}
if (MapView.debugFrameTime) {
GLES20.glFinish();
Log.d(TAG, "draw took " + (SystemClock.uptimeMillis() - start));
}
if (debugView) {
float mm = 0.5f;
float min = -mm;
float max = mm;
float ymax = mm * mHeight / mWidth;
mDebugCoords[0] = min;
mDebugCoords[1] = ymax;
mDebugCoords[2] = max;
mDebugCoords[3] = ymax;
mDebugCoords[4] = min;
mDebugCoords[5] = -ymax;
mDebugCoords[6] = max;
mDebugCoords[7] = -ymax;
PolygonRenderer.debugDraw(mProjMatrix, mDebugCoords, 0);
mapPosition.zoomLevel = -1;
mMapViewPosition.getMapPosition(mapPosition, mDebugCoords);
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0,
mapPosition.viewMatrix, 0);
PolygonRenderer.debugDraw(mMVPMatrix, mDebugCoords, 1);
}
GLRenderer.drawlock.unlock();
}
@ -701,54 +702,49 @@ public class GLRenderer implements GLSurfaceView.Renderer {
GLES20.glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id);
LineLayer ll = tile.lineLayers;
PolygonLayer pl = tile.polygonLayers;
boolean clipped = false;
int simpleShader = mRotate ? 0 : 1;
int simpleShader = 0; // mRotate ? 0 : 1;
for (; pl != null || ll != null;) {
int lnext = Integer.MAX_VALUE;
int pnext = Integer.MAX_VALUE;
for (Layer l = tile.layers.layers; l != null;) {
if (ll != null)
lnext = ll.layer;
switch (l.type) {
case Layer.POLYGON:
if (pl != null)
pnext = pl.layer;
if (pl != null && pnext < lnext) {
GLES20.glDisable(GL_BLEND);
pl = PolygonRenderer.drawPolygons(pos, pl, lnext, mvp, !clipped);
clipped = true;
} else {
// FIXME
if (!clipped) {
PolygonRenderer.drawPolygons(pos, null, 0, mvp, true);
GLES20.glDisable(GL_BLEND);
l = PolygonRenderer.draw(pos, l, mvp, !clipped, true);
clipped = true;
}
GLES20.glEnable(GL_BLEND);
ll = LineRenderer.drawLines(pos, ll, pnext, mvp, div,
simpleShader, tile.lineOffset);
break;
case Layer.LINE:
if (!clipped) {
PolygonRenderer.draw(pos, null, mvp, true, true);
clipped = true;
}
GLES20.glEnable(GL_BLEND);
l = LineRenderer.draw(pos, l, mvp, div, simpleShader,
tile.layers.lineOffset);
break;
}
}
if (tile.layers.symbolLayers != null) {
setMatrix(mvp, tile, div, false);
for (Layer l = tile.layers.symbolLayers; l != null;) {
l = TextureRenderer.draw(l, 1, mProjMatrix, mvp,
tile.layers.symbolOffset);
}
}
}
// TODO should check tile.proxies here
private static boolean drawProxyChild(MapTile tile) {
int drawn = 0;
for (int i = 0; i < 4; i++) {
if (tile.rel.child[i] == null)
if ((tile.proxies & 1 << i) == 0)
continue;
MapTile c = tile.rel.child[i].tile;
if (c == null)
continue;
// if (!isVisible(c)) {
// drawn++;
// continue;
// }
if (c.isReady) {
drawTile(c);
@ -812,13 +808,24 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mWidth = width;
mHeight = height;
// use this to scale only the view to see better which tiles are
// rendered
float s = MapViewPosition.VIEW_SCALE;
Matrix.frustumM(mProjMatrix, 0, -s * width, s * width,
s * height, -s * height, 1, 2);
float aspect = mHeight / (float) mWidth;
Matrix.translateM(mProjMatrix, 0, 0, 0, -MapViewPosition.VIEW_DISTANCE);
Matrix.frustumM(mProjMatrix, 0, -1 * s, 1 * s,
aspect * s, -aspect * s, MapViewPosition.VIEW_NEAR,
MapViewPosition.VIEW_FAR);
Matrix.setIdentityM(mTmpMatrix, 0);
Matrix.translateM(mTmpMatrix, 0, 0, 0, -MapViewPosition.VIEW_DISTANCE);
Matrix.multiplyMM(mProjMatrix, 0, mProjMatrix, 0, mTmpMatrix, 0);
if (debugView) {
// modify this to scale only the view, to see better which tiles are
// rendered
Matrix.setIdentityM(mMVPMatrix, 0);
Matrix.scaleM(mMVPMatrix, 0, 0.5f, 0.5f, 1);
Matrix.multiplyMM(mProjMatrix, 0, mMVPMatrix, 0, mProjMatrix, 0);
}
// set to zero: we modify the z value with polygon-offset for clipping
mProjMatrix[10] = 0;
@ -830,8 +837,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mMapView.redrawMap();
return;
}
mNewSurface = false;
mNewSurface = false;
mBufferMemoryUsage = 0;
int numTiles = (mWidth / (Tile.TILE_SIZE / 2) + 2)
@ -839,14 +846,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// Set up vertex buffer objects
int numVBO = (CACHE_TILES + (numTiles * 2));
int[] mVboIds = new int[numVBO];
GLES20.glGenBuffers(numVBO, mVboIds, 0);
GlUtils.checkGlError("glGenBuffers");
mVBOs = new ArrayList<VertexBufferObject>(numVBO);
for (int i = 1; i < numVBO; i++)
mVBOs.add(new VertexBufferObject(mVboIds[i]));
BufferObject.init(numVBO);
// Set up textures
TextRenderer.setup(numTiles);
@ -854,6 +854,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (mClearColor != null)
mUpdateColor = true;
vertexArray[0] = false;
vertexArray[1] = false;
// FIXME this should be synchronized
mMapView.redrawMap();
}
@ -862,20 +865,19 @@ public class GLRenderer implements GLSurfaceView.Renderer {
void clearTiles(int numTiles) {
mDrawTiles = new TilesData(numTiles);
mNextTiles = new TilesData(numTiles);
mMapPosition.zoomLevel = -1;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
String ext = GLES20.glGetString(GLES20.GL_EXTENSIONS);
Log.d(TAG, "Extensions: " + ext);
// String ext = GLES20.glGetString(GLES20.GL_EXTENSIONS);
// Log.d(TAG, "Extensions: " + ext);
LineRenderer.init();
PolygonRenderer.init();
TextRenderer.init();
mNewSurface = true;
// mUpdateColor = true;
TextureRenderer.init();
TextureObject.init(10);
// glEnable(GL_SCISSOR_TEST);
// glScissor(0, 0, mWidth, mHeight);
@ -883,51 +885,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
GLES20.glDisable(GLES20.GL_CULL_FACE);
GLES20.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
mNewSurface = true;
}
private boolean mNewSurface;
private static final boolean debugView = false;
}
//
// private static boolean isVisible(MapTile tile) {
// float dx, dy, scale, div = 1;
// MapPosition mapPosition = mMapPosition;
// int diff = mapPosition.zoomLevel - tile.zoomLevel;
//
// if (diff < 0)
// div = (1 << -diff);
// else if (diff > 0)
// div = (1.0f / (1 << diff));
//
// scale = mapPosition.scale / div;
// dx = (float) (tile.pixelX - mapPosition.x * div);
// dy = (float) (tile.pixelY - mapPosition.y * div);
//
// int size = Tile.TILE_SIZE;
// int sx = (int) (dx * scale);
// int sy = (int) (dy * scale);
//
// // FIXME little hack, need to do scanline check or sth
// // this kindof works for typical screen aspect
// if (mRotate) {
// int ssize = mWidth > mHeight ? mWidth : mHeight;
// ssize += Tile.TILE_SIZE;
// if (sy > ssize / 2 || sx > ssize / 2
// || sx + size * scale < -ssize / 2
// || sy + size * scale < -ssize / 2) {
// tile.isVisible = false;
// return false;
// }
// } else {
// if (sy > mHeight / 2 || sx > mWidth / 2
// || sx + size * scale < -mWidth / 2
// || sy + size * scale < -mHeight / 2) {
// tile.isVisible = false;
// return false;
// }
// }
// tile.isVisible = true;
//
// return true;
// }

View File

@ -12,14 +12,15 @@
* You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
import java.nio.ShortBuffer;
package org.oscim.renderer;
import org.oscim.core.MapPosition;
import org.oscim.renderer.layer.Layer;
import org.oscim.renderer.layer.LineLayer;
import org.oscim.theme.renderinstruction.Line;
import org.oscim.utils.GlUtils;
import org.oscim.view.MapPosition;
import android.graphics.Paint.Cap;
import android.opengl.GLES20;
import android.util.FloatMath;
import android.util.Log;
@ -27,7 +28,7 @@ import android.util.Log;
class LineRenderer {
private final static String TAG = "LineRenderer";
private static int NUM_VERTEX_SHORTS = 4;
// private static int NUM_VERTEX_SHORTS = 4;
private static final int LINE_VERTICES_DATA_POS_OFFSET = 0;
private static final int LINE_VERTICES_DATA_TEX_OFFSET = 4;
@ -40,6 +41,7 @@ class LineRenderer {
private static int[] hLineMatrix = new int[2];
private static int[] hLineScale = new int[2];
private static int[] hLineWidth = new int[2];
private static int[] hLineMode = new int[2];
static boolean init() {
lineProgram[0] = GlUtils.createProgram(Shaders.lineVertexShader,
@ -53,6 +55,7 @@ class LineRenderer {
hLineScale[0] = GLES20.glGetUniformLocation(lineProgram[0], "u_wscale");
hLineWidth[0] = GLES20.glGetUniformLocation(lineProgram[0], "u_width");
hLineColor[0] = GLES20.glGetUniformLocation(lineProgram[0], "u_color");
hLineMode[0] = GLES20.glGetUniformLocation(lineProgram[0], "u_mode");
hLineVertexPosition[0] = GLES20.glGetAttribLocation(lineProgram[0], "a_position");
hLineTexturePosition[0] = GLES20.glGetAttribLocation(lineProgram[0], "a_st");
@ -68,6 +71,7 @@ class LineRenderer {
hLineScale[1] = GLES20.glGetUniformLocation(lineProgram[1], "u_wscale");
hLineWidth[1] = GLES20.glGetUniformLocation(lineProgram[1], "u_width");
hLineColor[1] = GLES20.glGetUniformLocation(lineProgram[1], "u_color");
hLineMode[1] = GLES20.glGetUniformLocation(lineProgram[1], "u_mode");
hLineVertexPosition[1] = GLES20.glGetAttribLocation(lineProgram[1], "a_position");
hLineTexturePosition[1] = GLES20.glGetAttribLocation(lineProgram[1], "a_st");
@ -75,8 +79,8 @@ class LineRenderer {
return true;
}
static LineLayer drawLines(MapPosition pos, LineLayer layer, int next,
float[] matrix, float div, int mode, int bufferOffset) {
static Layer draw(MapPosition pos, Layer layer, float[] matrix, float div,
int mode, int bufferOffset) {
int zoom = pos.zoomLevel;
float scale = pos.scale;
@ -86,8 +90,20 @@ class LineRenderer {
GLES20.glUseProgram(lineProgram[mode]);
GLES20.glEnableVertexAttribArray(hLineVertexPosition[mode]);
GLES20.glEnableVertexAttribArray(hLineTexturePosition[mode]);
int va = hLineVertexPosition[mode];
if (!GLRenderer.vertexArray[va]) {
GLES20.glEnableVertexAttribArray(va);
GLRenderer.vertexArray[va] = true;
}
va = hLineTexturePosition[mode];
if (!GLRenderer.vertexArray[va]) {
GLES20.glEnableVertexAttribArray(va);
GLRenderer.vertexArray[va] = true;
}
// GLES20.glEnableVertexAttribArray(hLineVertexPosition[mode]);
// GLES20.glEnableVertexAttribArray(hLineTexturePosition[mode]);
GLES20.glVertexAttribPointer(hLineVertexPosition[mode], 2, GLES20.GL_SHORT,
false, 8, bufferOffset + LINE_VERTICES_DATA_POS_OFFSET);
@ -100,12 +116,14 @@ class LineRenderer {
// scale factor to map one pixel on tile to one pixel on screen:
// only works with orthographic projection
float s = scale / div;
float pixel = 2.0f / s;
float pixel = 0;
if (mode == 0)
pixel = 0;
if (mode == 1)
pixel = 1.5f / s;
GLES20.glUniform1f(hLineScale[mode], pixel);
int lineMode = 0;
GLES20.glUniform1i(hLineMode[mode], lineMode);
// line scale factor (for non fixed lines)
float lineScale = FloatMath.sqrt(s);
@ -115,10 +133,11 @@ class LineRenderer {
boolean strokeMaxZoom = zoom > TileGenerator.STROKE_MAX_ZOOM_LEVEL;
float width = 1;
LineLayer l = layer;
for (; l != null && l.layer < next; l = l.next) {
Layer l = layer;
for (; l != null && l.type == Layer.LINE; l = l.next) {
LineLayer ll = (LineLayer) l;
Line line = ll.line;
Line line = l.line;
if (line.fade != -1 && line.fade > zoom)
continue;
@ -134,23 +153,33 @@ class LineRenderer {
blur = false;
}
if (l.isOutline) {
for (LineLayer o = l.outlines; o != null; o = o.outlines) {
if (line.outline) {
for (LineLayer o = ll.outlines; o != null; o = o.outlines) {
if (o.line.fixed || strokeMaxZoom) {
width = (l.width + o.width) / s;
width = (ll.width + o.width) / s;
} else {
width = l.width / s + o.width / lineScale;
width = ll.width / s + o.width / lineScale;
}
GLES20.glUniform1f(hLineWidth[mode], width);
if (line.blur != 0) {
blurScale = (l.width + o.width) / s - (line.blur / s);
blurScale = (ll.width + o.width) / s - (line.blur / s);
GLES20.glUniform1f(hLineScale[mode], blurScale);
blur = true;
}
if (line.cap == Cap.ROUND) {
if (lineMode != 1) {
lineMode = 1;
GLES20.glUniform1i(hLineMode[mode], lineMode);
}
} else if (lineMode != 0) {
lineMode = 0;
GLES20.glUniform1i(hLineMode[mode], lineMode);
}
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, o.offset, o.verticesCnt);
}
} else {
@ -158,173 +187,37 @@ class LineRenderer {
if (line.fixed || strokeMaxZoom) {
// invert scaling of extrusion vectors so that line width
// stays the same.
width = l.width / s;
width = ll.width / s;
} else {
width = l.width / lineScale;
width = ll.width / lineScale;
}
GLES20.glUniform1f(hLineWidth[mode], width);
if (line.blur != 0) {
blurScale = (l.width / lineScale) * line.blur;
blurScale = (ll.width / lineScale) * line.blur;
GLES20.glUniform1f(hLineScale[mode], blurScale);
blur = true;
}
if (line.cap == Cap.ROUND) {
if (lineMode != 1) {
lineMode = 1;
GLES20.glUniform1i(hLineMode[mode], lineMode);
}
} else if (lineMode != 0) {
lineMode = 0;
GLES20.glUniform1i(hLineMode[mode], lineMode);
}
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, l.offset, l.verticesCnt);
}
}
GLES20.glDisableVertexAttribArray(hLineVertexPosition[mode]);
GLES20.glDisableVertexAttribArray(hLineTexturePosition[mode]);
// GLES20.glDisableVertexAttribArray(hLineVertexPosition[mode]);
// GLES20.glDisableVertexAttribArray(hLineTexturePosition[mode]);
return l;
}
static int sizeOf(LineLayer layers) {
int size = 0;
for (LineLayer l = layers; l != null; l = l.next)
size += l.verticesCnt;
size *= NUM_VERTEX_SHORTS;
return size;
}
static void compileLayerData(LineLayer layers, ShortBuffer sbuf) {
int pos = 0;
VertexPoolItem last = null, items = null;
for (LineLayer l = layers; l != null; l = l.next) {
if (l.isOutline)
continue;
for (VertexPoolItem item = l.pool; item != null; item = item.next) {
if (item.next == null) {
sbuf.put(item.vertices, 0, item.used);
} else {
// item.used = VertexPoolItem.SIZE;
sbuf.put(item.vertices);
}
last = item;
}
l.offset = pos;
pos += l.verticesCnt;
if (last != null) {
last.next = items;
items = l.pool;
}
l.pool = null;
l.curItem = null;
}
VertexPool.add(items);
}
// @SuppressLint("UseValueOf")
// private static final Boolean lock = new Boolean(true);
// private static final int POOL_LIMIT = 1500;
//
// static private LineLayer pool = null;
// static private int count = 0;
// static private int countAll = 0;
//
// static void finish() {
// synchronized (lock) {
// count = 0;
// countAll = 0;
// pool = null;
// }
// }
//
// static LineLayer get(int layer, Line line, float width, boolean outline)
// {
// synchronized (lock) {
//
// if (count == 0 && pool == null) {
// countAll++;
// return new LineLayer(layer, line, width, outline);
// }
// if (count > 0) {
// count--;
// } else {
// int c = 0;
// LineLayer tmp = pool;
//
// while (tmp != null) {
// c++;
// tmp = tmp.next;
// }
//
// Log.d("LineLayersl", "eek wrong count: " + c + " left");
// }
//
// LineLayer it = pool;
// pool = pool.next;
// it.next = null;
// it.layer = layer;
// it.line = line;
// it.isOutline = outline;
// it.width = width;
// return it;
// }
// }
//
// static void add(LineLayer layers) {
// if (layers == null)
// return;
//
// synchronized (lock) {
//
// // limit pool items
// if (countAll < POOL_LIMIT) {
// LineLayer last = layers;
//
// while (true) {
// count++;
//
// if (last.next == null)
// break;
//
// last = last.next;
// }
//
// last.next = pool;
// pool = layers;
//
// } else {
// int cleared = 0;
// LineLayer prev, tmp = layers;
// while (tmp != null) {
// prev = tmp;
// tmp = tmp.next;
//
// countAll--;
// cleared++;
//
// prev.next = null;
//
// }
// Log.d("LineLayers", "sum: " + countAll + " free: " + count + " freed "
// + cleared);
// }
//
// }
// }
//
static void clear(LineLayer layer) {
for (LineLayer l = layer; l != null; l = l.next) {
if (l.pool != null) {
VertexPool.add(l.pool);
l.pool = null;
l.curItem = null;
}
}
// LineLayers.add(layer);
}
}

View File

@ -12,18 +12,19 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer;
import java.util.ArrayList;
import java.util.Collections;
import org.oscim.core.MapPosition;
import org.oscim.core.Tile;
import org.oscim.generator.JobTile;
import org.oscim.renderer.layer.VertexPool;
import org.oscim.theme.RenderTheme;
import org.oscim.utils.GlConfigChooser;
import org.oscim.view.MapPosition;
import org.oscim.view.MapView;
import org.oscim.view.MapViewPosition;
import org.oscim.view.generator.JobTile;
import android.content.Context;
import android.opengl.GLSurfaceView;
@ -36,7 +37,7 @@ public class MapRenderer extends GLSurfaceView {
private GLRenderer mRenderer;
private static final int MAX_TILES_IN_QUEUE = 40;
private static final int CACHE_THRESHOLD = 50;
private static final int CACHE_THRESHOLD = 10;
private static MapView mMapView;
@ -52,6 +53,8 @@ public class MapRenderer extends GLSurfaceView {
// 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
@ -65,7 +68,8 @@ public class MapRenderer extends GLSurfaceView {
// private static int[] mZoomLevels;
private static float[] mTileCoords = new float[8];
private static int[] mBoundaryTiles = new int[8];
// private static int[] mBoundaryTiles = new int[8];
// used for passing tiles to be rendered from TileLoader(Main-Thread) to
// GLThread
@ -90,14 +94,14 @@ public class MapRenderer extends GLSurfaceView {
int xmax = 1 << mZoom;
for (int x = x1; x < x2; x++) {
// MapTile holder = null;
MapTile tile = null;
// boolean found = false;
if (cnt == max) {
Log.d(TAG, "reached max currentTiles " + max);
Log.d(TAG, "reached maximum for currentTiles " + max);
break;
}
// NOTE to myself: do not modify x, argh !!!
int xx = x;
if (x < 0 || x >= xmax) {
@ -107,12 +111,11 @@ public class MapRenderer extends GLSurfaceView {
else
xx = x - xmax;
if (xx < 0 || xx >= xmax) {
// Log.d(TAG, "tile out of bounds " + y + " " + xx);
if (xx < 0 || xx >= xmax)
continue;
}
}
// check if tile is already added
for (int i = 0; i < cnt; i++)
if (tiles[i].tileX == xx && tiles[i].tileY == y) {
tile = tiles[i];
@ -128,7 +131,28 @@ public class MapRenderer extends GLSurfaceView {
}
};
public MapRenderer(Context context, MapView mapView) {
// why not try a pattern every now and then?
// but should do the same for GLRenderer
private static MapRenderer SINGLETON;
public static MapRenderer create(Context context, MapView mapView) {
if (SINGLETON != null)
throw new IllegalStateException();
return SINGLETON = new MapRenderer(context, mapView);
}
public void destroy() {
SINGLETON = null;
// mRenderer = null;
// mTiles = null;
// mTilesLoaded = null;
// mJobList = null;
// mOverlays = null;
// ... free pools
}
private MapRenderer(Context context, MapView mapView) {
super(context);
mMapView = mapView;
@ -148,6 +172,7 @@ public class MapRenderer extends GLSurfaceView {
mJobList = new ArrayList<JobTile>();
mTiles = new ArrayList<MapTile>();
mTilesLoaded = new ArrayList<MapTile>(30);
mOverlays = new ArrayList<Overlay>(5);
VertexPool.init();
QuadTree.init();
@ -163,7 +188,7 @@ public class MapRenderer extends GLSurfaceView {
* @param clear
* whether to clear and reload all tiles
*/
public void updateMap(boolean clear) {
public void updateMap(final boolean clear) {
boolean changedPos = false;
if (mMapView == null)
@ -173,14 +198,24 @@ public class MapRenderer extends GLSurfaceView {
// make sure onDrawFrame is not running
GLRenderer.drawlock.lock();
// remove all tiles references
Log.d(TAG, "CLEAR");
for (MapTile t : mTiles)
clearTile(t);
Log.d(TAG, "CLEAR " + mInitial);
if (clear) {
for (MapTile t : mTiles)
clearTile(t);
} else {
VertexPool.init();
}
mTiles.clear();
mTilesLoaded.clear();
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)
@ -198,19 +233,25 @@ public class MapRenderer extends GLSurfaceView {
// mZoomLevels = mapInfo.zoomLevel;
GLRenderer.drawlock.unlock();
changedPos = true;
// .. make sure mMapPosition will be updated
mMapPosition.zoomLevel = -1;
mInitial = false;
}
MapPosition mapPosition = mMapPosition;
mMapViewPosition.getMapPosition(mapPosition, mTileCoords);
float[] coords = mTileCoords;
changedPos = mMapViewPosition.getMapPosition(mapPosition, coords);
if (!changedPos)
return;
float s = Tile.TILE_SIZE;
// load some additional tiles more than currently visible
float scale = mapPosition.scale * 0.75f;
float px = (float) mapPosition.x;
float py = (float) mapPosition.y;
float[] coords = mTileCoords;
int zdir = 0;
for (int i = 0; i < 8; i += 2) {
@ -218,32 +259,30 @@ public class MapRenderer extends GLSurfaceView {
coords[i + 1] = (py + coords[i + 1] / scale) / s;
}
for (int i = 0; i < 8; i++)
if (mBoundaryTiles[i] != (int) coords[i]) {
changedPos = true;
break;
}
for (int i = 0; i < 8; i++)
mBoundaryTiles[i] = (int) coords[i];
// this does not work reloably with tilt and rotation
// changedPos = false;
// for (int i = 0; i < 8; i++)
// if (mBoundaryTiles[i] != (int) coords[i]) {
// changedPos = true;
// break;
// }
// for (int i = 0; i < 8; i++)
// mBoundaryTiles[i] = (int) coords[i];
// TODO all following should probably be done in an idler instead
// to drain queued events. need to check how android handles things.
if (changedPos) {
updateVisibleList(mapPosition, zdir);
boolean changed = updateVisibleList(mapPosition, zdir);
if (!MapView.debugFrameTime)
requestRender();
if (!MapView.debugFrameTime)
requestRender();
if (changed) {
int remove = mTiles.size() - GLRenderer.CACHE_TILES;
if (remove > CACHE_THRESHOLD)
limitCache(mapPosition, remove);
limitLoadQueue();
} else {
if (!MapView.debugFrameTime)
requestRender();
}
}
@ -255,8 +294,9 @@ public class MapRenderer extends GLSurfaceView {
* the current MapPosition
* @param zdir
* zoom direction
* @return true if new tiles were loaded
*/
private static void updateVisibleList(MapPosition mapPosition, int zdir) {
private static boolean updateVisibleList(MapPosition mapPosition, int zdir) {
mJobList.clear();
// set non processed tiles to isLoading == false
@ -265,14 +305,16 @@ public class MapRenderer extends GLSurfaceView {
mScanBox.scan(mTileCoords, mapPosition.zoomLevel);
// Log.d(TAG, "visible: " + mCurrentTiles.cnt + "/" +
// mCurrentTiles.tiles.length);
GLRenderer.updateTiles(mCurrentTiles);
GLRenderer.updateTiles(mCurrentTiles, mOverlays);
// note: this sets isLoading == true for all job tiles
if (mJobList.size() > 0) {
updateTileDistances(mJobList, mapPosition);
Collections.sort(mJobList);
mMapView.addJobs(mJobList);
return true;
}
return false;
}
/* package */
@ -342,15 +384,15 @@ public class MapRenderer extends GLSurfaceView {
t.isLoading = false;
t.isReady = false;
LineRenderer.clear(t.lineLayers);
PolygonRenderer.clear(t.polygonLayers);
if (t.layers != null) {
t.layers.clear();
t.layers = null;
}
t.labels = null;
t.lineLayers = null;
t.polygonLayers = null;
if (t.vbo != null) {
GLRenderer.addVBO(t.vbo);
BufferObject.release(t.vbo);
t.vbo = null;
}
if (t.texture != null)
@ -364,7 +406,7 @@ public class MapRenderer extends GLSurfaceView {
byte zoom = mapPosition.zoomLevel;
long x = (long) mapPosition.x;
long y = (long) mapPosition.y;
// long center = Tile.TILE_SIZE << (zoom - 1);
int diff;
long dx, dy;
@ -380,6 +422,8 @@ public class MapRenderer extends GLSurfaceView {
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;
} else if (diff > 0) {
// tile zoom level is child of current
@ -392,6 +436,8 @@ public class MapRenderer 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));
@ -399,7 +445,8 @@ public class MapRenderer extends GLSurfaceView {
// 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);
@ -410,14 +457,13 @@ public class MapRenderer extends GLSurfaceView {
private static void limitCache(MapPosition mapPosition, int remove) {
int size = mTiles.size();
// remove orphaned tiles
// remove tiles that were never loaded
for (int i = 0; i < size;) {
MapTile t = mTiles.get(i);
// make sure tile cannot be used by GL or MapWorker Thread
if (t.isLocked() || t.isActive()) {
i++;
} else {
// Log.d(TAG, "remove empty tile" + t);
clearTile(t);
mTiles.remove(i);
remove--;
@ -432,32 +478,30 @@ public class MapRenderer extends GLSurfaceView {
Collections.sort(mTiles);
for (int i = 1; i < remove; i++) {
MapTile t = mTiles.remove(size - i);
synchronized (t) {
if (t.isLocked()) {
// dont remove tile used by renderthread
Log.d(TAG, "X not removing " + t
// + " " + t.isLocked
+ " " + t.distance);
mTiles.add(t);
continue;
}
if (t.isLoading) {
// NOTE: if we add tile back then on next limitCache
// the tile will be removed. clearTile could interfere with
// MapGenerator. so clear in passTile() instead.
// mTiles.add(t);
t.isLoading = false;
Log.d(TAG, "X cancel loading " + t + " " + t.distance);
continue;
}
clearTile(t);
if (t.isLocked()) {
// dont remove tile used by GLRenderer
Log.d(TAG, "X not removing " + t + " " + t.distance);
mTiles.add(t);
continue;
}
if (t.isLoading) {
// NOTE: if we add tile back and set loading=false, on next
// limitCache the tile will be removed. clearTile could
// interfere with TileGenerator. so clear in passTile()
// instead.
// ... no, this does not work either: when set loading to
// false tile could be added to load queue while still
// processed in TileGenerator => need tile.cancel flag.
// t.isLoading = false;
mTiles.add(t);
Log.d(TAG, "X cancel loading " + t + " " + t.distance);
continue;
}
clearTile(t);
}
}
@ -469,11 +513,11 @@ public class MapRenderer extends GLSurfaceView {
synchronized (mTilesLoaded) {
// remove tiles uploaded to vbo
// remove tiles already uploaded to vbo
for (int i = 0; i < size;) {
MapTile t = mTilesLoaded.get(i);
// rel == null means tile is already removed by limitCache
if (!t.newData || t.rel == null) {
if (!t.newData) {
mTilesLoaded.remove(i);
size--;
continue;
@ -484,32 +528,22 @@ public class MapRenderer extends GLSurfaceView {
if (size < MAX_TILES_IN_QUEUE)
return;
// Log.d(TAG, "queue: " + mTilesLoaded.size() + " " + size + " "
// + (size - MAX_TILES_IN_QUEUE / 2));
// clear loaded but not used tiles
for (int i = 0, n = size - MAX_TILES_IN_QUEUE / 2; i < n; n--) {
MapTile t = mTilesLoaded.get(i);
synchronized (t) {
if (t.rel == null) {
mTilesLoaded.remove(i);
continue;
}
if (t.isLocked()) {
// Log.d(TAG, "keep unused tile data: " + t + " " +
// t.isActive);
i++;
continue;
}
// Log.d(TAG, "remove unused tile data: " + t);
mTilesLoaded.remove(i);
mTiles.remove(t);
clearTile(t);
if (t.isLocked()) {
// Log.d(TAG, "keep unused tile data: " + t + " " +
// t.isActive);
i++;
continue;
}
// Log.d(TAG, "remove unused tile data: " + t);
mTilesLoaded.remove(i);
mTiles.remove(t);
clearTile(t);
}
}
}
@ -534,7 +568,7 @@ public class MapRenderer extends GLSurfaceView {
return true;
}
mRenderer.setVBO(tile);
tile.vbo = BufferObject.get();
if (tile.vbo == null) {
Log.d(TAG, "no VBOs left for " + tile);
@ -573,79 +607,4 @@ public class MapRenderer extends GLSurfaceView {
super.onSizeChanged(w, h, oldw, oldh);
}
// private static void updateVisibleList(MapPosition mapPosition, int zdir)
// {
// double x = mapPosition.x;
// double y = mapPosition.y;
// byte zoomLevel = mapPosition.zoomLevel;
// float scale = mapPosition.scale;
//
// double add = 1.0f / scale;
// int offsetX = (int) ((mWidth >> 1) * add) + Tile.TILE_SIZE;
// int offsetY = (int) ((mHeight >> 1) * add) + Tile.TILE_SIZE;
//
// long pixelRight = (long) x + offsetX;
// long pixelBottom = (long) y + offsetY;
// long pixelLeft = (long) x - offsetX;
// long pixelTop = (long) y - offsetY;
//
// int tileLeft = MercatorProjection.pixelXToTileX(pixelLeft, zoomLevel);
// int tileTop = MercatorProjection.pixelYToTileY(pixelTop, zoomLevel);
// int tileRight = MercatorProjection.pixelXToTileX(pixelRight, zoomLevel);
// int tileBottom = MercatorProjection.pixelYToTileY(pixelBottom,
// zoomLevel);
//
// mJobList.clear();
//
// // set non processed tiles to isLoading == false
// mMapView.addJobs(null);
//
// int tiles = 0;
// int max = mCurrentTiles.tiles.length - 1;
//
// // boolean fetchChildren = false;
// // boolean fetchParent = false;
// // boolean fetchProxy = false;
// // if (mZoomLevels != null) {
// // // check MapDatabase zoom-level-mapping
// // if (mZoomLevels[zoomLevel] == 0) {
// // mCurrentTiles.cnt = 0;
// // mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
// // return;
// // }
// //
// // if (mZoomLevels[zoomLevel] > zoomLevel) {
// // fetchChildren = true;
// // fetchProxy = true;
// //
// // } else if (mZoomLevels[zoomLevel] < zoomLevel) {
// // fetchParent = true;
// // fetchProxy = true;
// // }
// // }
//
// for (int yy = tileTop; yy <= tileBottom; yy++) {
// for (int xx = tileLeft; xx <= tileRight; xx++) {
//
// if (tiles == max)
// break;
//
// // MapTile tile =
// addTile(xx, yy, zoomLevel, zdir);
// // mCurrentTiles.tiles[tiles++] = tile;
// }
// }
//
// // pass new tile list to glThread
// mCurrentTiles.cnt = tiles;
// mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
//
// // note: this sets isLoading == true for all job tiles
// if (mJobList.size() > 0) {
// updateTileDistances(mJobList, mapPosition);
// Collections.sort(mJobList);
// mMapView.addJobs(mJobList);
// }
// }
}

View File

@ -12,9 +12,10 @@
* You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer;
import org.oscim.view.generator.JobTile;
import org.oscim.generator.JobTile;
import org.oscim.renderer.layer.Layers;
class MapTile extends JobTile {
@ -22,26 +23,15 @@ class MapTile extends JobTile {
* VBO layout: - 16 bytes fill coordinates, n bytes polygon vertices, m
* bytes lines vertices
*/
VertexBufferObject vbo;
/**
* polygonOffset in vbo is always 16 bytes,
*/
int lineOffset;
BufferObject vbo;
TextTexture texture;
/**
* Tile data set by TileGenerator:
*/
LineLayer lineLayers;
PolygonLayer polygonLayers;
TextItem labels;
/**
* tile is used by render thread. set by updateVisibleList (main thread).
*/
// boolean isLocked;
Layers layers;
/**
* tile has new data to upload to gl
@ -59,7 +49,7 @@ class MapTile extends JobTile {
boolean isVisible;
/**
* pointer to access relatives in TileTree
* pointer to access relatives in QuadTree
*/
QuadTree rel;
@ -74,12 +64,16 @@ class MapTile extends JobTile {
// counting the tiles that use this tile as proxy
byte refs;
byte locked;
// this tile sits in fo another tile. e.g. x:-1,y:0,z:1 for x:1,y:0
// used when this tile sits in fo another tile.
// e.g. x:-1,y:0,z:1 for x:1,y:0
MapTile holder;
MapTile(int tileX, int tileY, byte zoomLevel) {
super(tileX, tileY, zoomLevel);
}
boolean isActive() {
return isLoading || newData || isReady;
}
@ -146,9 +140,4 @@ class MapTile extends JobTile {
}
proxies = 0;
}
MapTile(int tileX, int tileY, byte zoomLevel) {
super(tileX, tileY, zoomLevel);
}
}

View File

@ -0,0 +1,190 @@
/*
* Copyright 2012, Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.renderer;
import java.io.IOException;
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.layer.LineLayer;
import org.oscim.renderer.layer.SymbolItem;
import org.oscim.renderer.layer.SymbolLayer;
import org.oscim.theme.renderinstruction.BitmapUtils;
import org.oscim.theme.renderinstruction.Line;
import org.oscim.view.MapView;
import android.graphics.Color;
import android.graphics.Paint.Cap;
import android.opengl.GLES20;
import android.opengl.Matrix;
public class Overlay {
BufferObject vbo;
Layers layers;
TextItem labels;
TextTexture texture;
// flag to set when data is ready for (re)compilation.
boolean newData;
boolean isReady;
MapPosition mMapPosition;
float drawScale;
private boolean first = true;
Overlay() {
mMapPosition = new MapPosition();
layers = new Layers();
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));
//
// float[] ppoints = {
// 0, 256,
// 0, 0,
// 256, 0,
// 256, 256,
// };
// 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);
layers.symbolLayers = sl;
}
synchronized boolean onTouch() {
return true;
}
// /////////////// called from GLRender Thread ////////////////////////
// use synchronized (this){} when updating 'layers' from another thread
synchronized void update(MapView mapView) {
// keep position constant (or update layer relative to new position)
// mapView.getMapViewPosition().getMapPosition(mMapPosition, null);
if (first) {
// fix at initial position
mapView.getMapViewPosition().getMapPosition(mMapPosition, null);
first = false;
// pass layers to be uploaded and drawn to GL Thread
// afterwards never modify 'layers' outside of this function!
newData = true;
}
}
float[] mvp = new float[16];
synchronized void render(MapPosition pos, float[] mv, float[] proj) {
float div = 1;
setMatrix(pos, mv);
Matrix.multiplyMM(mvp, 0, proj, 0, mv, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo.id);
for (Layer l = layers.layers; l != null;) {
if (l.type == Layer.POLYGON) {
GLES20.glDisable(GLES20.GL_BLEND);
l = PolygonRenderer.draw(pos, l, mvp, true, false);
} else {
GLES20.glEnable(GLES20.GL_BLEND);
l = LineRenderer.draw(pos, l, mvp, div, 0, layers.lineOffset);
}
}
for (Layer l = layers.symbolLayers; l != null;) {
l = TextureRenderer.draw(l, 1, proj, mv, layers.symbolOffset);
}
}
private void setMatrix(MapPosition mPos, float[] matrix) {
MapPosition oPos = mMapPosition;
float div = 1;
byte z = oPos.zoomLevel;
int diff = mPos.zoomLevel - z;
if (diff < 0)
div = (1 << -diff);
else if (diff > 0)
div = (1.0f / (1 << diff));
float x = (float) (oPos.x - mPos.x * div);
float y = (float) (oPos.y - mPos.y * div);
// flip around date-line
float max = (Tile.TILE_SIZE << z);
if (x < -max / 2)
x = max + x;
else if (x > max / 2)
x = x - max;
float scale = mPos.scale / div;
Matrix.setIdentityM(matrix, 0);
// translate relative to map center
matrix[12] = x * scale;
matrix[13] = y * scale;
scale = (mPos.scale / oPos.scale) / div;
// scale to tile to world coordinates
scale /= GLRenderer.COORD_MULTIPLIER;
matrix[0] = scale;
matrix[5] = scale;
Matrix.multiplyMM(matrix, 0, mPos.viewMatrix, 0, matrix, 0);
}
}

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer;
import static android.opengl.GLES20.GL_BLEND;
import static android.opengl.GLES20.GL_EQUAL;
@ -38,17 +38,18 @@ import static android.opengl.GLES20.glVertexAttribPointer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.oscim.core.MapPosition;
import org.oscim.renderer.layer.Layer;
import org.oscim.renderer.layer.PolygonLayer;
import org.oscim.utils.GlUtils;
import org.oscim.view.MapPosition;
import android.opengl.GLES20;
class PolygonRenderer {
// private static final String TAG = "PolygonRenderer";
private static final int NUM_VERTEX_SHORTS = 2;
// private static final int NUM_VERTEX_SHORTS = 2;
private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0;
private static final int STENCIL_BITS = 8;
@ -88,9 +89,6 @@ class PolygonRenderer {
/* do not modify stencil buffer */
glStencilMask(0);
/* only draw where nothing was drawn yet */
glEnable(GLES20.GL_DEPTH_TEST);
for (int c = mStart; c < mCount; c++) {
PolygonLayer l = mFillPolys[c];
@ -162,14 +160,25 @@ class PolygonRenderer {
// stencil buffer index to start fill
private static int mStart;
static PolygonLayer drawPolygons(MapPosition pos, PolygonLayer layer, int next,
float[] matrix, boolean first) {
static Layer draw(MapPosition pos, Layer layer,
float[] matrix, boolean first, boolean clip) {
int zoom = pos.zoomLevel;
float scale = pos.scale;
glUseProgram(polygonProgram);
GLES20.glEnableVertexAttribArray(hPolygonVertexPosition);
int va = hPolygonVertexPosition;
if (!GLRenderer.vertexArray[va]) {
GLES20.glEnableVertexAttribArray(va);
GLRenderer.vertexArray[va] = true;
}
va = va == 0 ? 1 : 0;
if (GLRenderer.vertexArray[va]) {
GLES20.glDisableVertexAttribArray(va);
GLRenderer.vertexArray[va] = false;
}
// GLES20.glEnableVertexAttribArray(hPolygonVertexPosition);
glVertexAttribPointer(hPolygonVertexPosition, 2, GLES20.GL_SHORT,
false, 0, POLYGON_VERTICES_DATA_POS_OFFSET);
@ -179,8 +188,6 @@ class PolygonRenderer {
// use stencilbuffer method for polygon drawing
glEnable(GL_STENCIL_TEST);
PolygonLayer l = layer;
if (first) {
mCount = 0;
mStart = 0;
@ -188,12 +195,15 @@ class PolygonRenderer {
mStart = mCount;
}
for (; l != null && l.layer < next; l = l.next) {
Layer l = layer;
for (; l != null && l.type == Layer.POLYGON; l = l.next) {
PolygonLayer pl = (PolygonLayer) l;
// fade out polygon layers (set in RederTheme)
if (l.area.fade > 0 && l.area.fade > zoom)
if (pl.area.fade > 0 && pl.area.fade > zoom)
continue;
if (mCount == 0) {
if (mCount == mStart) {
// clear stencilbuffer (tile region)
// disable drawing to framebuffer
@ -205,7 +215,7 @@ class PolygonRenderer {
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
if (first) {
if (clip) {
// draw clip-region into depth buffer:
// this is used for lines and polygons
@ -214,14 +224,15 @@ class PolygonRenderer {
// to prevent overdraw gl_less restricts
// the clip to the area where no other
// tile was drawn
// tile has drawn
GLES20.glDepthFunc(GLES20.GL_LESS);
}
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (first) {
if (clip) {
first = false;
clip = false;
// dont modify depth buffer
GLES20.glDepthMask(false);
// only draw to this tile
@ -232,23 +243,26 @@ class PolygonRenderer {
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
// no need for depth test while drawing stencil
glDisable(GLES20.GL_DEPTH_TEST);
if (clip)
glDisable(GLES20.GL_DEPTH_TEST);
} else if (mCount == mStart) {
// disable drawing to framebuffer
glColorMask(false, false, false, false);
// never pass the test: always apply fail op
glStencilFunc(GLES20.GL_ALWAYS, 0, 0xFF);
// stencil op for stencil method polygon drawing
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
// no need for depth test while drawing stencil
glDisable(GLES20.GL_DEPTH_TEST);
}
// else if (mCount == mStart) {
// // disable drawing to framebuffer
// glColorMask(false, false, false, false);
//
// // never pass the test: always apply fail op
// glStencilFunc(GLES20.GL_ALWAYS, 0, 0xFF);
//
// // stencil op for stencil method polygon drawing
// glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
//
// // no need for depth test while drawing stencil
// if (clip)
// glDisable(GLES20.GL_DEPTH_TEST);
// }
mFillPolys[mCount] = l;
mFillPolys[mCount] = pl;
// set stencil mask to draw to
glStencilMask(1 << mCount++);
@ -257,15 +271,23 @@ class PolygonRenderer {
// draw up to 8 layers into stencil buffer
if (mCount == STENCIL_BITS) {
/* only draw where nothing was drawn yet */
if (clip)
glEnable(GLES20.GL_DEPTH_TEST);
fillPolygons(zoom, scale);
mCount = 0;
mStart = 0;
}
}
if (mCount > 0)
fillPolygons(zoom, scale);
if (mCount > 0) {
/* only draw where nothing was drawn yet */
if (clip)
glEnable(GLES20.GL_DEPTH_TEST);
fillPolygons(zoom, scale);
}
// maybe reset start when only few layers left in stencil buffer
// if (mCount > 5){
// mCount = 0;
@ -274,19 +296,20 @@ class PolygonRenderer {
glDisable(GL_STENCIL_TEST);
if (first)
if (clip && first)
drawDepthClip();
GLES20.glDisableVertexAttribArray(hPolygonVertexPosition);
// GLES20.glDisableVertexAttribArray(hPolygonVertexPosition);
return l;
}
private static float[] debugFillColor = { 0.3f, 0.0f, 0.0f, 0.3f };
private static float[] debugFillColor2 = { 0.0f, 0.3f, 0.0f, 0.3f };
private static ByteBuffer mDebugFill;
static void debugDraw(float[] matrix, float[] coords) {
static void debugDraw(float[] matrix, float[] coords, int color) {
mDebugFill = ByteBuffer.allocateDirect(32).order(ByteOrder.nativeOrder());
FloatBuffer buf = mDebugFill.asFloatBuffer();
@ -303,12 +326,15 @@ class PolygonRenderer {
glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0);
glUniform4fv(hPolygonColor, 1, debugFillColor, 0);
if (color == 0)
glUniform4fv(hPolygonColor, 1, debugFillColor, 0);
else
glUniform4fv(hPolygonColor, 1, debugFillColor2, 0);
glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GlUtils.checkGlError("draw debug");
GLES20.glDisableVertexAttribArray(hPolygonVertexPosition);
// GLES20.glDisableVertexAttribArray(hPolygonVertexPosition);
}
static void drawDepthClip() {
@ -322,55 +348,4 @@ class PolygonRenderer {
glColorMask(true, true, true, true);
GLES20.glDepthFunc(GLES20.GL_EQUAL);
}
static int sizeOf(PolygonLayer layers) {
int size = 0;
for (PolygonLayer l = layers; l != null; l = l.next)
size += l.verticesCnt;
size *= NUM_VERTEX_SHORTS;
return size;
}
static void compileLayerData(PolygonLayer layers, ShortBuffer sbuf) {
int pos = 4;
VertexPoolItem last = null, items = null;
for (PolygonLayer l = layers; l != null; l = l.next) {
for (VertexPoolItem item = l.pool; item != null; item = item.next) {
if (item.next == null) {
sbuf.put(item.vertices, 0, item.used);
} else {
// item.used = VertexPoolItem.SIZE;
sbuf.put(item.vertices);
}
last = item;
}
l.offset = pos;
pos += l.verticesCnt;
if (last != null) {
last.next = items;
items = l.pool;
}
l.pool = null;
}
VertexPool.add(items);
}
static void clear(PolygonLayer layers) {
for (PolygonLayer l = layers; l != null; l = l.next) {
if (l.pool != null)
VertexPool.add(l.pool);
}
}
}

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer;
import android.util.Log;
@ -37,17 +37,9 @@ class QuadTree {
MapTile tile;
static void init() {
pool = null;
root = new QuadTree();
root.parent = root;
// QuadTree t;
// for (int i = 0; i < 200; i++) {
// t = new QuadTree();
// t.parent = pool;
// pool = t;
// }
}
static boolean remove(MapTile t) {
@ -90,8 +82,6 @@ class QuadTree {
int y = tile.tileY;
int z = tile.zoomLevel;
QuadTree cur;
// if (x < 0 || x >= 1 << z) {
// Log.d(TAG, "invalid position");
// return null;
@ -109,7 +99,7 @@ class QuadTree {
leaf.refs++;
cur = leaf.child[id];
QuadTree cur = leaf.child[id];
if (cur != null) {
leaf = cur;

View File

@ -15,7 +15,7 @@
/* ported from Polymaps: Layer.js Copyright (c) 2010, SimpleGeo and Stamen Design */
package org.oscim.view.renderer;
package org.oscim.renderer;
import android.util.FloatMath;
import android.util.Log;
@ -103,6 +103,7 @@ public abstract class ScanBox {
scanSpans(ca, bc);
}
// FIXME
private static final int MAX_SLOPE = 4;
private void scanSpans(Edge e0, Edge e1) {

View File

@ -13,9 +13,9 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer;
class Shaders {
public final class Shaders {
final static String lineVertexShader = ""
+ "precision mediump float;"
@ -54,40 +54,119 @@ class Shaders {
+ "precision mediump float;"
+ "uniform float u_wscale;"
+ "uniform float u_width;"
+ "uniform int u_mode;"
+ "uniform vec4 u_color;"
+ "varying vec2 v_st;"
+ "const float zero = 0.0;"
+ "void main() {"
+ " float len;"
+ " if (v_st.t == zero)"
+ " len = abs(v_st.s);"
+ " if (u_mode == 0)"
+ " len = u_width - abs(v_st.s);"
+ " else "
+ " len = length(v_st);"
+ " len = u_width - length(v_st);"
// fade to alpha. u_wscale is the width in pixel which should be
// faded, u_width - len the position of this fragment on the
// perpendicular to this line segment
+ " gl_FragColor = smoothstep(zero, u_wscale, u_width - len) * u_color;"
+ " vec4 color = u_color;"
+ " if (len < u_wscale)"
+ " color *= len / u_wscale;"
+ " gl_FragColor = color;"
// smoothstep(zero, u_wscale, u_width - len) * u_color;"
+ "}";
// final static String lineFragmentShader = ""
// + "#extension GL_OES_standard_derivatives : enable\n"
// + "precision mediump float;\n"
// + "uniform float u_wscale;"
// + "uniform float u_width;"
// + "uniform vec4 u_color;"
// + "varying vec2 v_st;"
// + "const float zero = 0.0;"
// + "const vec4 col1 = vec4(0.5,0.0,0.0,0.5);"
// + "const vec4 col2 = vec4(0.0,0.0,0.5,0.5);"
// + "void main() {"
// + " vec4 color = u_color;"
// + " float width = u_width;"
// + " float len;"
// + " if (v_st.t == zero)"
// + " len = abs(v_st.s);"
// + " else "
// + " len = length(v_st);"
// + " vec2 st_width = fwidth(v_st);"
// + " float fuzz = max(st_width.s, st_width.t);"
// // + " if (v_st.s > 0.0){"
// // + " color = col1;"
// + " color *= (1.0 - len) / (fuzz + u_wscale);"
// // + " }else{"
// // + " color = col2;"
// // + " color *= 1.0 - (fuzz + u_wscale) / (len - 1.0);"
// // + " }"
// + " gl_FragColor = color;"
// + "}";
// final static String lineFragmentShader = ""
// + "#extension GL_OES_standard_derivatives : enable\n"
// + "precision mediump float;\n"
// + "uniform float u_wscale;"
// + "uniform float u_width;"
// + "uniform vec4 u_color;"
// + "varying vec2 v_st;"
// + "const float zero = 0.0;"
// + "const vec4 col1 = vec4(0.5,0.0,0.0,0.5);"
// + "const vec4 col2 = vec4(0.0,0.0,0.5,0.5);"
// + "void main() {"
// + " vec4 color = u_color;"
// + " float width = u_width;"
// + " float len;"
// + " if (v_st.t == zero)"
// + " len = abs(v_st.s);"
// + " else "
// + " len = length(v_st);"
// + " vec2 st_width = fwidth(v_st);"
// + " float fuzz = max(st_width.s, st_width.t);"
// + " if (u_width > 1.0) fuzz *= 1.2;"
// + " color *= (u_width - len) / (fuzz + u_wscale);"
// + " if (v_st.s > 0.0){"
// + " if (u_width - len < fuzz + u_wscale)"
// + " color = col1 * (u_width - len) / (fuzz + u_wscale);"
// + " }else{"
// + " if (u_width - len < fuzz + u_wscale)"
// + " color = col2 * (u_width - len) / (fuzz + u_wscale);"
// + "}"
// // + " color *= (fuzz + u_wscale);"
// // " color *= smoothstep(zero, fuzz + u_wscale, u_width - len);"
// + " gl_FragColor = color;"
// + "}";
final static String lineFragmentShader = ""
+ "#extension GL_OES_standard_derivatives : enable\n"
+ "precision mediump float;\n"
+ "uniform float u_wscale;"
+ "uniform float u_width;"
+ "uniform int u_mode;"
+ "uniform vec4 u_color;"
+ "varying vec2 v_st;"
// + "const vec4 col1 = vec4(0.5,0.0,0.0,0.5);"
// + "const vec4 col2 = vec4(0.0,0.0,0.5,0.5);"
+ "const float zero = 0.0;"
+ "void main() {"
+ " vec4 color = u_color;"
+ " float width = u_width;"
+ " float len;"
+ " if (v_st.t == zero)"
+ " len = abs(v_st.s);"
+ " if (u_mode == 0)"
+ " len = u_width - abs(v_st.s);"
+ " else "
+ " len = length(v_st);"
+ " vec2 st_width = fwidth(v_st);"
+ " float fuzz = max(st_width.s, st_width.t) * 1.5;"
+ " color *= smoothstep(zero, fuzz + u_wscale, u_width - len);"
+ " len = u_width - length(v_st);"
+ " vec2 st_width = fwidth(v_st);"
+ " float fuzz = max(st_width.s, st_width.t);"
// + " if (u_width > 1.0) fuzz *= 1.2;"
+ " fuzz += u_wscale;"
+ " if (len < fuzz){"
// + " if (v_st.s > zero)"
+ " color *= len / fuzz;"
// + " else"
// + " color = col2 * (u_width - len) / fuzz;"
+ " }"
+ " gl_FragColor = color;"
+ "}";
@ -113,17 +192,18 @@ class Shaders {
+ "uniform mat4 u_mv;"
+ "uniform mat4 u_proj;"
+ "uniform float u_scale;"
+ "uniform float u_swidth;"
+ "varying vec2 tex_c;"
+ "const vec2 div = vec2(1.0/4096.0,1.0/2048.0);"
+ "const vec2 div = vec2(1.0/2048.0,1.0/2048.0);"
+ "const float coord_scale = 0.125;"
+ "void main() {"
+ " vec4 pos;"
+ " if (mod(vertex.x, 2.0) == 0.0){"
+ " pos = u_proj * (u_mv * vec4(vertex.xy + vertex.zw * u_scale, 0.0, 1.0));"
+ " } else {"
// place as billboard
// // place as billboard
+ " vec4 dir = u_mv * vec4(vertex.xy, 0.0, 1.0);"
+ " pos = u_proj * (dir + vec4(vertex.zw * coord_scale, 0.0, 0.0));"
+ " pos = u_proj * (dir + vec4(vertex.zw * (coord_scale * u_swidth), 0.0, 0.0));"
+ " }"
+ " gl_Position = pos;"
+ " tex_c = tex_coord * div;"
@ -134,7 +214,7 @@ class Shaders {
// + "attribute vec4 vertex;"
// + "attribute vec2 tex_coord;"
// + "uniform mat4 mvp;"
// + "uniform mat4 rotation;"
// + "uniform mat4 viewMatrix;"
// + "uniform float scale;"
// + "varying vec2 tex_c;"
// + "const vec2 div = vec2(1.0/4096.0,1.0/2048.0);"
@ -143,7 +223,7 @@ class Shaders {
// + " if (mod(vertex.x, 2.0) == 0.0){"
// + " pos = mvp * vec4(vertex.xy + vertex.zw / scale, 0.0, 1.0);"
// + " } else {"
// + " vec4 dir = rotation * vec4(vertex.zw / scale, 0.0, 1.0);"
// + " vec4 dir = viewMatrix * vec4(vertex.zw / scale, 0.0, 1.0);"
// + " pos = mvp * vec4(vertex.xy + dir.xy, 0.0, 1.0);"
// + " }"
// + " pos.z = 0.0;"
@ -156,7 +236,7 @@ class Shaders {
// + "attribute vec4 vertex;"
// + "attribute vec2 tex_coord;"
// + "uniform mat4 mvp;"
// + "uniform mat4 rotation;"
// + "uniform mat4 viewMatrix;"
// + "uniform float scale;"
// + "varying vec2 tex_c;"
// + "const vec2 div = vec2(1.0/4096.0,1.0/2048.0);"
@ -165,7 +245,7 @@ class Shaders {
// +
// " gl_Position = mvp * vec4(vertex.xy + vertex.zw / scale, 0.0, 1.0);"
// + " } else {"
// + " vec4 dir = rotation * vec4(vertex.zw / scale, 0.0, 1.0);"
// + " vec4 dir = viewMatrix * vec4(vertex.zw / scale, 0.0, 1.0);"
// + " gl_Position = mvp * vec4(vertex.xy + dir.xy, 0.0, 1.0);"
// + " }"
// + " tex_c = tex_coord * div;"

View File

@ -12,37 +12,33 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer;
import org.oscim.theme.renderinstruction.Caption;
import org.oscim.theme.renderinstruction.PathText;
import org.oscim.theme.renderinstruction.Text;
public class TextItem {
TextItem next;
final float x, y;
final String text;
final Caption caption;
final PathText path;
final String string;
final Text text;
final float width;
short x1, y1, x2, y2;
public TextItem(float x, float y, String text, Caption caption) {
public TextItem(float x, float y, String string, Text text) {
this.x = x;
this.y = y;
this.string = string;
this.text = text;
this.caption = caption;
this.width = caption.paint.measureText(text);
this.path = null;
this.width = text.paint.measureText(string);
}
public TextItem(float x, float y, String text, PathText pathText, float width) {
public TextItem(float x, float y, String string, Text text, float width) {
this.x = x;
this.y = y;
this.string = string;
this.text = text;
this.path = pathText;
this.caption = null;
this.width = width;
}

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@ -30,7 +30,9 @@ import android.util.FloatMath;
import android.util.Log;
public class TextRenderer {
private final static int TEXTURE_WIDTH = 512;
private static String TAG = "TextRenderer";
private final static int TEXTURE_WIDTH = 256;
private final static int TEXTURE_HEIGHT = 256;
private final static float SCALE = 8.0f;
private final static int LBIT_MASK = 0xfffffffe;
@ -58,6 +60,7 @@ public class TextRenderer {
private static int hTextProjectionMatrix;
private static int hTextVertex;
private static int hTextScale;
private static int hTextScreenScale;
private static int hTextTextureCoord;
private static Paint mPaint = new Paint(Color.BLACK);
@ -86,6 +89,7 @@ public class TextRenderer {
hTextMVMatrix = GLES20.glGetUniformLocation(mTextProgram, "u_mv");
hTextProjectionMatrix = GLES20.glGetUniformLocation(mTextProgram, "u_proj");
hTextScale = GLES20.glGetUniformLocation(mTextProgram, "u_scale");
hTextScreenScale = GLES20.glGetUniformLocation(mTextProgram, "u_swidth");
hTextVertex = GLES20.glGetAttribLocation(mTextProgram, "vertex");
hTextTextureCoord = GLES20.glGetAttribLocation(mTextProgram, "tex_coord");
@ -235,16 +239,10 @@ public class TextRenderer {
TextItem t = tile.labels;
float yy;
short x1, x2, x3, x4, y1, y2, y3, y4;
for (int i = 0; t != null && i < max; t = t.next, i++) {
if (t.caption != null) {
height = (int) (t.caption.fontHeight) + 2 * mFontPadY;
} else {
height = (int) (t.path.fontHeight) + 2 * mFontPadY;
}
height = (int) (t.text.fontHeight) + 2 * mFontPadY;
width = t.width + 2 * mFontPadX;
if (height > advanceY)
@ -256,35 +254,26 @@ public class TextRenderer {
advanceY = (int) height;
}
if (t.caption != null) {
yy = y + (height - 1) - t.caption.fontDescent - mFontPadY;
} else {
yy = y + (height - 1) - t.path.fontDescent - mFontPadY;
}
yy = y + (height - 1) - t.text.fontDescent - mFontPadY;
if (yy > TEXTURE_HEIGHT) {
Log.d(TAG, "reached max labels");
continue;
break;
// continue;
}
if (t.caption != null) {
if (t.caption.stroke != null)
mCanvas.drawText(t.text, x + t.width / 2, yy, t.caption.stroke);
if (t.text.stroke != null)
mCanvas.drawText(t.string, x + t.width / 2, yy, t.text.stroke);
mCanvas.drawText(t.text, x + t.width / 2, yy, t.caption.paint);
} else {
if (t.path.stroke != null)
mCanvas.drawText(t.text, x + t.width / 2, yy, t.path.stroke);
mCanvas.drawText(t.string, x + t.width / 2, yy, t.text.paint);
mCanvas.drawText(t.text, x + t.width / 2, yy, t.path.paint);
}
if (width > TEXTURE_WIDTH)
width = TEXTURE_WIDTH;
float hw = width / 2.0f;
float hh = height / 2.0f;
short x1, x2, x3, x4, y1, y2, y3, y4;
if (t.caption != null) {
if (t.text.caption) {
x1 = x3 = (short) (SCALE * (-hw));
y1 = y3 = (short) (SCALE * (hh));
x2 = x4 = (short) (SCALE * (hw));
@ -330,11 +319,8 @@ public class TextRenderer {
short v2 = (short) (SCALE * (y + height));
// pack caption/way-text info in lowest bit
short tx;
if (t.caption == null)
tx = (short) ((int) (SCALE * t.x) & LBIT_MASK | 0);
else
tx = (short) ((int) (SCALE * t.x) & LBIT_MASK | 1);
int tmp = (int) (SCALE * t.x) & LBIT_MASK;
short tx = (short) (tmp | (t.text.caption ? 1 : 0));
short ty = (short) (SCALE * t.y);
@ -393,8 +379,6 @@ public class TextRenderer {
return true;
}
private static String TAG = "TextRenderer";
static void compileTextures() {
int offset = 0;
TextTexture tex;
@ -422,32 +406,34 @@ public class TextRenderer {
static void beginDraw(float scale, float[] projection) {
GLES20.glUseProgram(mTextProgram);
GLES20.glEnableVertexAttribArray(hTextTextureCoord);
GLES20.glEnableVertexAttribArray(hTextVertex);
// GLES20.glEnableVertexAttribArray(hTextTextureCoord);
// GLES20.glEnableVertexAttribArray(hTextVertex);
int va = hTextTextureCoord;
if (!GLRenderer.vertexArray[va]) {
GLES20.glEnableVertexAttribArray(va);
GLRenderer.vertexArray[va] = true;
}
va = hTextVertex;
if (!GLRenderer.vertexArray[va]) {
GLES20.glEnableVertexAttribArray(va);
GLRenderer.vertexArray[va] = true;
}
GLES20.glUniform1f(hTextScale, scale);
GLES20.glUniform1f(hTextScreenScale, 1f / GLRenderer.mWidth);
GLES20.glUniformMatrix4fv(hTextProjectionMatrix, 1, false, projection, 0);
if (debug) {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
mShortBuffer.clear();
mShortBuffer.put(debugVertices, 0, 16);
mShortBuffer.flip();
GLES20.glVertexAttribPointer(hTextVertex, 2,
GLES20.GL_SHORT, false, 8, mShortBuffer);
mShortBuffer.position(2);
GLES20.glVertexAttribPointer(hTextTextureCoord, 2,
GLES20.GL_SHORT, false, 8, mShortBuffer);
} else {
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesVBO);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVerticesVBO);
}
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesVBO);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVerticesVBO);
}
static void endDraw() {
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
GLES20.glDisableVertexAttribArray(hTextTextureCoord);
GLES20.glDisableVertexAttribArray(hTextVertex);
// GLES20.glDisableVertexAttribArray(hTextTextureCoord);
// GLES20.glDisableVertexAttribArray(hTextVertex);
}
static void drawTile(MapTile tile, float[] matrix) {
@ -456,19 +442,14 @@ public class TextRenderer {
GLES20.glUniformMatrix4fv(hTextMVMatrix, 1, false, matrix, 0);
if (debug) {
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
} else {
GLES20.glVertexAttribPointer(hTextVertex, 4,
GLES20.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 8));
GLES20.glVertexAttribPointer(hTextVertex, 4,
GLES20.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 8));
GLES20.glVertexAttribPointer(hTextTextureCoord, 2,
GLES20.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 8)
+ 8);
GLES20.glVertexAttribPointer(hTextTextureCoord, 2,
GLES20.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 8)
+ 8);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, (tile.texture.length / 24) *
INDICES_PER_SPRITE, GLES20.GL_UNSIGNED_SHORT, 0);
}
GLES20.glDrawElements(GLES20.GL_TRIANGLES, (tile.texture.length / 24) *
INDICES_PER_SPRITE, GLES20.GL_UNSIGNED_SHORT, 0);
}
}

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer;
public class TextTexture {
@ -22,12 +22,11 @@ public class TextTexture {
int offset;
MapTile tile;
String[] text;
TextTexture(int textureID) {
vertices = new short[TextRenderer.MAX_LABELS *
TextRenderer.VERTICES_PER_SPRITE *
TextRenderer.SHORTS_PER_VERTICE];
id = textureID;
}

View File

@ -0,0 +1,97 @@
/*
* Copyright 2012 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.renderer;
import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;
public class TextureObject {
private static TextureObject pool;
public static synchronized TextureObject get() {
TextureObject to;
if (pool == null) {
init(10);
}
to = pool;
pool = pool.next;
to.next = null;
return to;
}
public static synchronized void release(TextureObject to) {
to.next = pool;
pool = to;
}
public static void uploadTexture(TextureObject to, Bitmap bitmap,
int format, int type, int w, int h) {
if (to == null) {
Log.d("...", "no fckn texture!");
return;
}
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, to.id);
if (to.width == w && to.height == h)
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, bitmap, format, type);
else {
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, format, bitmap, type, 0);
to.width = w;
to.height = h;
}
}
static void init(int num) {
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
to = new TextureObject(textureIds[i]);
to.next = pool;
pool = to;
}
}
public TextureObject next;
int id;
int width;
int height;
// vertex offset from which this texture is referenced
// or store texture id with vertex?
int offset;
TextureObject(int id) {
this.id = id;
}
}

View File

@ -0,0 +1,139 @@
/*
* Copyright 2012 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.renderer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import org.oscim.renderer.layer.Layer;
import org.oscim.renderer.layer.TextureLayer;
import org.oscim.utils.GlUtils;
import android.opengl.GLES20;
public class TextureRenderer {
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;
private static int mIndicesVBO;
final static int INDICES_PER_SPRITE = 6;
final static int VERTICES_PER_SPRITE = 4;
final static int SHORTS_PER_VERTICE = 6;
// per texture
public final static int MAX_ITEMS = 40;
static void init() {
mTextureProgram = GlUtils.createProgram(Shaders.textVertexShader,
Shaders.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");
int bufferSize = MAX_ITEMS * VERTICES_PER_SPRITE
* SHORTS_PER_VERTICE * (Short.SIZE / 8);
ByteBuffer buf = ByteBuffer.allocateDirect(bufferSize)
.order(ByteOrder.nativeOrder());
ShortBuffer mShortBuffer = buf.asShortBuffer();
// Setup triangle indices
short[] indices = new short[MAX_ITEMS * INDICES_PER_SPRITE];
int len = indices.length;
short j = 0;
for (int i = 0; i < len; i += INDICES_PER_SPRITE, j += VERTICES_PER_SPRITE) {
indices[i + 0] = (short) (j + 0);
indices[i + 1] = (short) (j + 1);
indices[i + 2] = (short) (j + 2);
indices[i + 3] = (short) (j + 2);
indices[i + 4] = (short) (j + 3);
indices[i + 5] = (short) (j + 0);
}
mShortBuffer.clear();
mShortBuffer.put(indices, 0, len);
mShortBuffer.flip();
int[] mVboIds = new int[1];
GLES20.glGenBuffers(1, mVboIds, 0);
mIndicesVBO = mVboIds[0];
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesVBO);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, len * (Short.SIZE / 8),
mShortBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
}
static Layer draw(Layer layer, float scale, float[] projection,
float matrix[], int offset) {
GLES20.glUseProgram(mTextureProgram);
GlUtils.checkGlError("draw texture1");
int va = hTextureTexCoord;
if (!GLRenderer.vertexArray[va]) {
GLES20.glEnableVertexAttribArray(va);
GLRenderer.vertexArray[va] = true;
}
va = hTextureVertex;
if (!GLRenderer.vertexArray[va]) {
GLES20.glEnableVertexAttribArray(va);
GLRenderer.vertexArray[va] = true;
}
TextureLayer tl = (TextureLayer) layer;
GlUtils.checkGlError("draw texture2.");
GLES20.glUniform1f(hTextureScale, scale);
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");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tl.textures.id);
GlUtils.checkGlError("draw texture4");
GlUtils.checkGlError("draw texture5");
GLES20.glVertexAttribPointer(hTextureVertex, 4,
GLES20.GL_SHORT, false, 12, offset);
GlUtils.checkGlError("draw texture..");
GLES20.glVertexAttribPointer(hTextureTexCoord, 2,
GLES20.GL_SHORT, false, 12, offset + 8);
GlUtils.checkGlError("draw texture...");
GLES20.glDrawElements(GLES20.GL_TRIANGLES, (tl.verticesCnt / 4)
* INDICES_PER_SPRITE, GLES20.GL_UNSIGNED_SHORT, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
GlUtils.checkGlError("draw texture");
return layer.next;
}
}

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer;
import org.oscim.core.MercatorProjection;
import org.oscim.core.Tag;
@ -21,16 +21,21 @@ import org.oscim.core.WebMercator;
import org.oscim.database.IMapDatabase;
import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.QueryResult;
import org.oscim.generator.JobTile;
import org.oscim.renderer.layer.Layer;
import org.oscim.renderer.layer.Layers;
import org.oscim.renderer.layer.LineLayer;
import org.oscim.renderer.layer.PolygonLayer;
import org.oscim.renderer.layer.SymbolItem;
import org.oscim.renderer.layer.SymbolLayer;
import org.oscim.theme.IRenderCallback;
import org.oscim.theme.RenderTheme;
import org.oscim.theme.renderinstruction.Area;
import org.oscim.theme.renderinstruction.Caption;
import org.oscim.theme.renderinstruction.Line;
import org.oscim.theme.renderinstruction.PathText;
import org.oscim.theme.renderinstruction.RenderInstruction;
import org.oscim.theme.renderinstruction.Text;
import org.oscim.view.DebugSettings;
import org.oscim.view.MapView;
import org.oscim.view.generator.JobTile;
import android.graphics.Bitmap;
import android.graphics.Paint;
@ -45,9 +50,9 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
private static final double PI180 = (Math.PI / 180) / 1000000.0;
private static final double PIx4 = Math.PI * 4;
private static final double STROKE_INCREASE = Math.sqrt(2);
private static final byte LAYERS = 11;
private static final double f900913 = 20037508.342789244;
static final byte STROKE_MIN_ZOOM_LEVEL = 12;
static final byte STROKE_MAX_ZOOM_LEVEL = 17;
@ -58,13 +63,15 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
private MapTile mCurrentTile;
// coordinates of the currently processed way
private float[] mCoords;
private short[] mIndices;
private LineLayer mLineLayers;
private PolygonLayer mPolyLayers;
// current line layer, will be added to outline layers
private LineLayer mCurLineLayer;
private PolygonLayer mCurPolyLayer;
// layer data prepared for rendering
private Layers mLayers;
private TextItem mLabels;
@ -74,10 +81,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
private float mStrokeScale = 1.0f;
private boolean mProjected;
// private boolean mProjectedResult;
private float mSimplify;
// private boolean firstMatch;
// private boolean prevClosed;
private RenderInstruction[] mRenderInstructions = null;
@ -126,8 +130,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
mTagName = null;
if (mMapProjection != null)
{
if (mMapProjection != null) {
long x = mCurrentTile.pixelX;
long y = mCurrentTile.pixelY + Tile.TILE_SIZE;
long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel;
@ -137,7 +140,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
long dy = (y - (z >> 1));
if (mMapProjection == WebMercator.NAME) {
double div = f900913 / (z >> 1);
double div = WebMercator.f900913 / (z >> 1);
// divy = f900913 / (z >> 1);
mPoiX = (float) (longitude / div - dx);
mPoiY = (float) (latitude / div + dy);
@ -147,6 +150,8 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
mPoiX = (float) (longitude / divx - dx);
double sinLat = Math.sin(latitude * PI180);
mPoiY = (float) (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy);
// TODO remove this, only used for mapsforge maps
if (mPoiX < -10 || mPoiX > Tile.TILE_SIZE + 10 || mPoiY < -10
|| mPoiY > Tile.TILE_SIZE + 10)
return;
@ -230,45 +235,45 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
}
@Override
public void renderAreaCaption(Caption caption) {
public void renderAreaCaption(Text text) {
// Log.d(TAG, "renderAreaCaption: " + mTagName);
if (mTagName == null)
return;
if (caption.textKey == mTagEmptyName.key) {
if (text.textKey == mTagEmptyName.key) {
TextItem t = new TextItem(mCoords[0], mCoords[1], mTagName.value, caption);
TextItem t = new TextItem(mCoords[0], mCoords[1], mTagName.value, text);
t.next = mLabels;
mLabels = t;
}
}
@Override
public void renderPointOfInterestCaption(Caption caption) {
public void renderPointOfInterestCaption(Text text) {
// Log.d(TAG, "renderPointOfInterestCaption: " + mPoiX + " " + mPoiY +
// " " + mTagName);
if (mTagName == null)
return;
if (caption.textKey == mTagEmptyName.key) {
TextItem t = new TextItem(mPoiX, mPoiY, mTagName.value, caption);
if (text.textKey == mTagEmptyName.key) {
TextItem t = new TextItem(mPoiX, mPoiY, mTagName.value, text);
t.next = mLabels;
mLabels = t;
}
}
@Override
public void renderWayText(PathText pathText) {
public void renderWayText(Text text) {
// Log.d(TAG, "renderWayText: " + mTagName);
if (mTagName == null)
return;
if (pathText.textKey == mTagEmptyName.key && mTagName.value != null) {
if (text.textKey == mTagEmptyName.key && mTagName.value != null) {
mLabels = WayDecorator.renderText(mCoords, mTagName.value, pathText, 0,
mLabels = WayDecorator.renderText(mCoords, mTagName.value, text, 0,
mIndices[0], mLabels);
}
}
@ -286,67 +291,47 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
}
@Override
public void renderPointOfInterestSymbol(Bitmap symbol) {
// TODO Auto-generated method stub
public void renderPointOfInterestSymbol(Bitmap bitmap) {
// Log.d(TAG, "add symbol");
if (mLayers.symbolLayers == null)
mLayers.symbolLayers = new SymbolLayer();
SymbolLayer sl = (SymbolLayer) mLayers.symbolLayers;
SymbolItem it = new SymbolItem();
it.x = mPoiX;
it.y = mPoiY;
it.bitmap = bitmap;
it.billboard = true;
sl.addSymbol(it);
}
private int countLines;
private int countNodes;
@Override
public void renderWay(Line line, int level) {
projectToTile();
if (line.outline && mCurLineLayer == null)
return;
float w = line.width;
int numLayer = (mDrawingLayer * 2) + level;
if (!line.fixed) {
w *= mStrokeScale;
w *= mProjectionScaleFactor;
}
LineLayer lineLayer = null;
int numLayer = mDrawingLayer + level;
LineLayer l = mLineLayers;
if (mCurLineLayer != null && mCurLineLayer.layer == numLayer) {
lineLayer = mCurLineLayer;
} else if (l == null || l.layer > numLayer) {
// insert new layer at start
lineLayer = new LineLayer(numLayer, line, w, line.outline);
// lineLayer = LineLayers.get(numLayer, line, w, false);
lineLayer.next = l;
mLineLayers = lineLayer;
} else {
while (l != null) {
// found layer
if (l.layer == numLayer) {
lineLayer = l;
break;
}
// insert new layer between current and next layer
if (l.next == null || l.next.layer > numLayer) {
lineLayer = new LineLayer(numLayer, line, w, line.outline);
// lineLayer = LineLayers.get(numLayer, line, w, false);
lineLayer.next = l.next;
l.next = lineLayer;
break;
}
l = l.next;
}
}
if (lineLayer == null) {
mCurLineLayer = null;
LineLayer lineLayer = (LineLayer) mLayers.getLayer(numLayer, Layer.LINE);
if (lineLayer == null)
return;
if (lineLayer.line == null) {
lineLayer.line = line;
float w = line.width;
if (!line.fixed) {
w *= mStrokeScale;
w *= mProjectionScaleFactor;
}
lineLayer.width = w;
}
if (line.outline) {
lineLayer.addOutline(mCurLineLayer);
return;
@ -367,38 +352,12 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
int numLayer = mDrawingLayer + level;
PolygonLayer layer = null;
PolygonLayer l = mPolyLayers;
if (mCurPolyLayer != null && mCurPolyLayer.layer == numLayer) {
layer = mCurPolyLayer;
} else if (l == null || l.layer > numLayer) {
// insert new layer at start
layer = new PolygonLayer(numLayer, area);
layer.next = l;
mPolyLayers = layer;
} else {
while (l != null) {
if (l.layer == numLayer) {
layer = l;
break;
}
// insert new layer between current and next layer
if (l.next == null || l.next.layer > numLayer) {
layer = new PolygonLayer(numLayer, area);
layer.next = l.next;
l.next = layer;
break;
}
l = l.next;
}
}
PolygonLayer layer = (PolygonLayer) mLayers.getLayer(numLayer, Layer.POLYGON);
if (layer == null)
return;
mCurPolyLayer = layer;
if (layer.area == null)
layer.area = area;
layer.addPolygon(mCoords, mIndices);
}
@ -430,7 +389,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
mDebugDrawUnmatched = debugSettings.mDrawUnmatchted;
if (tile.newData || tile.isReady) {
// fixed now....
// should be fixed now.
Log.d(TAG, "XXX tile already loaded "
+ tile + " "
+ tile.newData + " "
@ -446,22 +405,19 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
else
setScaleStrokeWidth(STROKE_MAX_ZOOM_LEVEL);
// firstMatch = true;
countLines = 0;
countNodes = 0;
// acount for area changes with latitude
mProjectionScaleFactor = 0.5f + (float) (0.5 / Math.cos(MercatorProjection
.pixelYToLatitude(tile.pixelY, tile.zoomLevel)
* (Math.PI / 180)));
mLayers = new Layers();
if (mMapDatabase.executeQuery(tile, this) != QueryResult.SUCCESS) {
Log.d(TAG, "Failed loading: " + tile);
LineRenderer.clear(mLineLayers);
PolygonRenderer.clear(mPolyLayers);
mLineLayers = null;
mPolyLayers = null;
mLayers.clear();
mLayers = null;
mLabels = null;
mCurLineLayer = null;
tile.isLoading = false;
return false;
}
@ -478,15 +434,12 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
TileGenerator.renderTheme.matchWay(this, debugTagBox, (byte) 0, false, true);
}
tile.lineLayers = mLineLayers;
tile.polygonLayers = mPolyLayers;
tile.layers = mLayers;
tile.labels = mLabels;
mCurPolyLayer = null;
mCurLineLayer = null;
mLineLayers = null;
mPolyLayers = null;
mLayers = null;
mLabels = null;
mCurLineLayer = null;
return true;
}
@ -542,6 +495,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
return mRenderInstructions != null;
}
// TODO move this to Projection classes
private boolean projectToTile() {
if (mProjected || mMapProjection == null)
return true;
@ -558,13 +512,12 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel;
float min = mSimplify;
double divx, divy;
double divx, divy = 0;
long dx = (x - (z >> 1));
long dy = (y - (z >> 1));
if (useWebMercator) {
divx = f900913 / (z >> 1);
divy = f900913 / (z >> 1);
divx = WebMercator.f900913 / (z >> 1);
} else {
divx = 180000000.0 / (z >> 1);
divy = z / PIx4;
@ -584,7 +537,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
if (useWebMercator) {
lon = (float) (coords[pos] / divx - dx);
lat = (float) (coords[pos + 1] / divy + dy);
lat = (float) (coords[pos + 1] / divx + dy);
} else {
lon = (float) ((coords[pos]) / divx - dx);
double sinLat = Math.sin(coords[pos + 1] * PI180);

View File

@ -12,9 +12,9 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer;
import org.oscim.theme.renderinstruction.PathText;
import org.oscim.theme.renderinstruction.Text;
import org.oscim.utils.GeometryUtils;
import android.util.FloatMath;
@ -99,7 +99,7 @@ final class WayDecorator {
// }
// }
static TextItem renderText(float[] coordinates, String text, PathText pathText,
static TextItem renderText(float[] coordinates, String string, Text text,
int pos, int len, TextItem textItems) {
TextItem items = textItems;
TextItem t = null;
@ -175,7 +175,7 @@ final class WayDecorator {
} else if (segmentLengthInPixel > minWidth) {
if (wayNameWidth < 0) {
wayNameWidth = pathText.paint.measureText(text);
wayNameWidth = text.paint.measureText(string);
}
if (segmentLengthInPixel > wayNameWidth + 25) {
@ -227,7 +227,7 @@ final class WayDecorator {
if (x1 - 10 < t2.x2 && t2.x1 - 10 < x2 && top - 10 < bot2
&& top2 - 10 < bot) {
if (t2.text.equals(text)) {
if (t2.string.equals(string)) {
intersects = true;
break;
}
@ -256,8 +256,8 @@ final class WayDecorator {
}
// if (t == null)
t = new TextItem(x1 + (x2 - x1) / 2, y1 + (y2 - y1) / 2, text,
pathText, wayNameWidth);
t = new TextItem(x1 + (x2 - x1) / 2, y1 + (y2 - y1) / 2, string,
text, wayNameWidth);
t.x1 = (short) x1;
t.y1 = (short) y1;

View File

@ -0,0 +1,37 @@
/*
* Copyright 2012 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.renderer.layer;
public class Layer {
public final static byte LINE = 0;
public final static byte POLYGON = 1;
public final static byte WAYTEXT = 2;
public final static byte POITEXT = 3;
public final static byte SYMBOL = 4;
public final static byte BITMAP = 5;
public byte type;
public Layer next;
int layer;
// number of vertices this layer holds
public int verticesCnt;
// vertices offset of this layer in VBO
public int offset;
VertexPoolItem pool;
protected VertexPoolItem curItem;
}

View File

@ -0,0 +1,166 @@
/*
* Copyright 2012 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.renderer.layer;
import java.nio.ShortBuffer;
import org.oscim.renderer.TextureObject;
import android.util.Log;
public class Layers {
public Layer layers;
public int lineOffset;
public Layer symbolLayers;
public int symbolOffset;
private Layer mCurLayer;
public Layer getLayer(int level, byte type) {
Layer l = layers;
Layer ret = null;
if (mCurLayer != null && mCurLayer.layer == level) {
ret = mCurLayer;
} else if (l == null || l.layer > level) {
// insert new layer at start
l = null;
} else {
while (true) {
if (l.layer == level) {
// found layer
ret = l;
break;
}
if (l.next == null || l.next.layer > level) {
// insert new layer between current and next layer
break;
}
l = l.next;
}
}
if (ret == null) {
if (type == Layer.LINE)
ret = new LineLayer(level);
else
ret = new PolygonLayer(level);
if (l == null) {
ret.next = layers;
layers = ret;
} else {
ret.next = l.next;
l.next = ret;
}
} else if (ret.type != type) {
Log.d("...", "wrong layer type " + ret.type + " " + type);
// FIXME thorw exception
return null;
}
return ret;
}
private static int LINE_VERTEX_SHORTS = 4;
private static int POLY_VERTEX_SHORTS = 2;
private static int TEXTURE_VERTEX_SHORTS = 6;
public int getSize() {
int size = 0;
for (Layer l = layers; l != null; l = l.next) {
if (l.type == Layer.LINE)
size += l.verticesCnt * LINE_VERTEX_SHORTS;
else
size += l.verticesCnt * POLY_VERTEX_SHORTS;
}
for (Layer l = symbolLayers; l != null; l = l.next) {
size += l.verticesCnt * TEXTURE_VERTEX_SHORTS;
}
return size;
}
public void compile(ShortBuffer sbuf, boolean addFill) {
// offset from fill coordinates
int pos = 0;
if (addFill)
pos = 4;
// add polygons first, needed to get the offsets right...
addLayerItems(sbuf, layers, Layer.POLYGON, pos);
lineOffset = sbuf.position() * 2; // * short-bytes
addLayerItems(sbuf, layers, Layer.LINE, 0);
symbolOffset = sbuf.position() * 2; // * short-bytes
for (Layer l = symbolLayers; l != null; l = l.next) {
SymbolLayer sl = (SymbolLayer) l;
sl.compile(sbuf);
}
}
private static void addLayerItems(ShortBuffer sbuf, Layer l, byte type, int pos) {
VertexPoolItem last = null, items = null;
for (; l != null; l = l.next) {
if (l.type != type)
continue;
for (VertexPoolItem it = l.pool; it != null; it = it.next) {
if (it.next == null)
sbuf.put(it.vertices, 0, it.used);
else
sbuf.put(it.vertices);
last = it;
}
if (last == null)
continue;
l.offset = pos;
pos += l.verticesCnt;
last.next = items;
items = l.pool;
last = null;
l.pool = null;
l.curItem = null;
}
VertexPool.release(items);
}
public void clear() {
// FIXME collect pool and add as a whole
for (Layer l = layers; l != null; l = l.next) {
if (l.pool != null) {
VertexPool.release(l.pool);
l.pool = null;
l.curItem = null;
}
}
for (Layer l = symbolLayers; l != null; l = l.next) {
SymbolLayer sl = (SymbolLayer) l;
if (sl.textures != null)
TextureObject.release(sl.textures);
}
}
}

View File

@ -12,15 +12,16 @@
* You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer.layer;
import org.oscim.core.Tile;
import org.oscim.renderer.GLRenderer;
import org.oscim.theme.renderinstruction.Line;
import android.graphics.Paint.Cap;
import android.util.FloatMath;
class LineLayer {
public final class LineLayer extends Layer {
private static final float COORD_SCALE = GLRenderer.COORD_MULTIPLIER;
// scale factor mapping extrusion vector to short values
@ -29,33 +30,26 @@ class LineLayer {
// coordinates
private static final int DIR_MASK = 0xFFFFFFFC;
// next layer
LineLayer next;
// lines referenced by this outline layer
LineLayer outlines;
public LineLayer outlines;
public Line line;
public float width;
Line line;
float width;
boolean isOutline;
int layer;
// boolean isOutline;
VertexPoolItem pool;
protected VertexPoolItem curItem;
// number of vertices this layer holds
int verticesCnt;
// vertices offset of this layer in VBO
int offset;
LineLayer(int layer, Line line, float width, boolean outline) {
LineLayer(int layer) {
this.layer = layer;
this.width = width;
this.line = line;
this.isOutline = outline;
this.type = Layer.LINE;
}
void addOutline(LineLayer link) {
// LineLayer(int layer, Line line, float width, boolean outline) {
// this.layer = layer;
// this.width = width;
// this.line = line;
// // this.isOutline = outline;
// }
public void addOutline(LineLayer link) {
for (LineLayer l = outlines; l != null; l = l.outlines)
if (link == l)
return;
@ -69,7 +63,7 @@ class LineLayer {
* (https://github.com/olofsj/GLMap/) by olofsj
*/
void addLine(float[] points, short[] index, boolean closed) {
public void addLine(float[] points, short[] index, boolean closed) {
float x, y, nextX, nextY, prevX, prevY;
float a, ux, uy, vx, vy, wx, wy;
@ -108,7 +102,6 @@ class LineLayer {
continue;
}
//
closed = false;
// amount of vertices used

View File

@ -12,32 +12,25 @@
* You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer.layer;
import org.oscim.core.Tile;
import org.oscim.renderer.GLRenderer;
import org.oscim.theme.renderinstruction.Area;
class PolygonLayer {
public final class PolygonLayer extends Layer {
private static final float S = GLRenderer.COORD_MULTIPLIER;
PolygonLayer next;
Area area;
public Area area;
VertexPoolItem pool;
protected VertexPoolItem curItem;
int verticesCnt;
int offset;
final int layer;
PolygonLayer(int layer, Area area) {
PolygonLayer(int layer) {
this.layer = layer;
this.area = area;
this.type = Layer.POLYGON;
curItem = VertexPool.get();
pool = curItem;
}
void addPolygon(float[] points, short[] index) {
public void addPolygon(float[] points, short[] index) {
short center = (short) ((Tile.TILE_SIZE >> 1) * S);
VertexPoolItem si = curItem;

View File

@ -0,0 +1,29 @@
/*
* Copyright 2012 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.renderer.layer;
import android.graphics.Bitmap;
public class SymbolItem {
SymbolItem next;
public Bitmap bitmap;
public float x;
public float y;
public boolean billboard;
// center, top, bottom, left, right, top-left...
byte placement;
}

View File

@ -0,0 +1,200 @@
/*
* Copyright 2012 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.renderer.layer;
import java.nio.ShortBuffer;
import org.oscim.renderer.TextureObject;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.RectF;
import android.opengl.GLUtils;
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 int TEXTURE_WIDTH = 256;
private final static int TEXTURE_HEIGHT = 256;
private final static float SCALE = 8.0f;
private static short[] mVertices;
private static Bitmap mBitmap;
private static Canvas mCanvas;
private static int mBitmapFormat;
private static int mBitmapType;
SymbolItem symbols;
public SymbolLayer() {
if (mBitmap == null) {
mBitmap = Bitmap.createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT,
Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mBitmapFormat = GLUtils.getInternalFormat(mBitmap);
mBitmapType = GLUtils.getType(mBitmap);
//
mVertices = new short[40 * 24];
}
}
public void addSymbol(SymbolItem item) {
verticesCnt += 4;
SymbolItem it = symbols;
for (; it != null; it = it.next) {
if (it.bitmap == item.bitmap) {
item.next = it.next;
it.next = item;
return;
}
}
item.next = symbols;
symbols = item;
}
private final static int LBIT_MASK = 0xfffffffe;
private final RectF mRect = new RectF();
// TODO ... reuse texture when only symbol position changed
public void compile(ShortBuffer sbuf) {
int pos = 0;
short buf[] = mVertices;
int advanceY = 0;
float x = 0;
float y = 0;
mBitmap.eraseColor(Color.TRANSPARENT);
for (SymbolItem it = symbols; it != null;) {
// add bitmap
float width = it.bitmap.getWidth();
float height = it.bitmap.getHeight();
if (height > advanceY)
advanceY = (int) height;
if (x + width > TEXTURE_WIDTH) {
x = 0;
y += advanceY;
advanceY = (int) (height + 0.5f);
if (y + height > TEXTURE_HEIGHT) {
Log.d(TAG, "reached max symbols");
// need to sync bitmap upload somehow???
TextureObject to = TextureObject.get();
TextureObject.uploadTexture(to, mBitmap,
mBitmapFormat, mBitmapType,
TEXTURE_WIDTH, TEXTURE_HEIGHT);
to.next = textures;
textures = to;
sbuf.put(buf, 0, pos);
pos = 0;
}
}
mRect.left = x;
mRect.top = y;
mRect.right = x + width;
mRect.bottom = y + height;
// Log.d("...", "draw " + x + " " + y + " " + width + " " + height);
mCanvas.drawBitmap(it.bitmap, null, mRect, null);
// mCanvas.drawBitmap(it.bitmap, x, y, null);
float hw = width / 2.0f;
float hh = height / 2.0f;
short x1, x2, x3, x4, y1, y2, y3, y4;
x1 = x3 = (short) (SCALE * (-hw));
x2 = x4 = (short) (SCALE * (hw));
y1 = y3 = (short) (SCALE * (hh));
y2 = y4 = (short) (SCALE * (-hh));
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
for (SymbolItem it2 = it;; it2 = it2.next) {
if (it2 == null || it2.bitmap != it.bitmap) {
it = it2;
break;
}
// add vertices
short tx = (short) ((int) (SCALE * it2.x) & LBIT_MASK | (it2.billboard ? 1 : 0));
short ty = (short) (SCALE * it2.y);
// top-left
buf[pos++] = tx;
buf[pos++] = ty;
buf[pos++] = x1;
buf[pos++] = y1;
buf[pos++] = u1;
buf[pos++] = v2;
// top-right
buf[pos++] = tx;
buf[pos++] = ty;
buf[pos++] = x2;
buf[pos++] = y3;
buf[pos++] = u2;
buf[pos++] = v2;
// bot-right
buf[pos++] = tx;
buf[pos++] = ty;
buf[pos++] = x4;
buf[pos++] = y4;
buf[pos++] = u2;
buf[pos++] = v1;
// bot-left
buf[pos++] = tx;
buf[pos++] = ty;
buf[pos++] = x3;
buf[pos++] = y2;
buf[pos++] = u1;
buf[pos++] = v1;
x += width + 1;
}
}
TextureObject to = TextureObject.get();
TextureObject.uploadTexture(to, mBitmap,
mBitmapFormat, mBitmapType,
TEXTURE_WIDTH, TEXTURE_HEIGHT);
to.next = textures;
textures = to;
sbuf.put(buf, 0, pos);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2012 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
@ -12,8 +12,11 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer.layer;
public class SymbolLayer {
import org.oscim.renderer.TextItem;
public final class TextLayer extends TextureLayer {
TextItem labels;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2012 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
@ -12,8 +12,11 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer.layer;
public class TextureLayer {
import org.oscim.renderer.TextureObject;
public abstract class TextureLayer extends Layer {
public TextureObject textures;
}

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer.layer;
import android.util.Log;
@ -23,7 +23,7 @@ public class VertexPool {
static private int count = 0;
static private int countAll = 0;
static synchronized void init() {
public static synchronized void init() {
count = 0;
countAll = 0;
pool = null;
@ -61,7 +61,7 @@ public class VertexPool {
// private static float load = 1.0f;
// private static int loadCount = 0;
static synchronized void add(VertexPoolItem items) {
static synchronized void release(VertexPoolItem items) {
if (items == null)
return;
@ -86,7 +86,8 @@ public class VertexPool {
last.next = pool;
pool = items;
// Log.d("Pool", "added: " + (count - pcnt) + " " + count + " " + countAll
// Log.d("Pool", "added: " + (count - pcnt) + " " + count + " " +
// countAll
// + " load: " + (load / loadCount));
} else {

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.view.renderer;
package org.oscim.renderer.layer;
public class VertexPoolItem {
final short[] vertices;

View File

@ -15,9 +15,8 @@
package org.oscim.theme;
import org.oscim.theme.renderinstruction.Area;
import org.oscim.theme.renderinstruction.Caption;
import org.oscim.theme.renderinstruction.Line;
import org.oscim.theme.renderinstruction.PathText;
import org.oscim.theme.renderinstruction.Text;
import android.graphics.Bitmap;
import android.graphics.Paint;
@ -36,14 +35,6 @@ public interface IRenderCallback {
*/
void renderArea(Area area, int level);
/**
* Renders an area caption with the given text.
*
* @param caption
* the text to be rendered.
*/
void renderAreaCaption(Caption caption);
/**
* Renders an area symbol with the given bitmap.
*
@ -52,14 +43,6 @@ public interface IRenderCallback {
*/
void renderAreaSymbol(Bitmap symbol);
/**
* Renders a point of interest caption with the given text.
*
* @param caption
* the text to be rendered.
*/
void renderPointOfInterestCaption(Caption caption);
/**
* Renders a point of interest circle with the given parameters.
*
@ -105,8 +88,25 @@ public interface IRenderCallback {
/**
* Renders a way with the given text along the way path.
*
* @param pathText
* @param text
* ...
*/
void renderWayText(PathText pathText);
void renderWayText(Text text);
/**
* Renders an area caption with the given text.
*
* @param text
* the text to be rendered.
*/
void renderAreaCaption(Text text);
/**
* Renders a point of interest caption with the given text.
*
* @param text
* the text to be rendered.
*/
void renderPointOfInterestCaption(Text text);
}

View File

@ -26,13 +26,12 @@ import javax.xml.parsers.SAXParserFactory;
import org.oscim.theme.renderinstruction.Area;
import org.oscim.theme.renderinstruction.AreaLevel;
import org.oscim.theme.renderinstruction.Caption;
import org.oscim.theme.renderinstruction.Circle;
import org.oscim.theme.renderinstruction.Line;
import org.oscim.theme.renderinstruction.LineSymbol;
import org.oscim.theme.renderinstruction.PathText;
import org.oscim.theme.renderinstruction.RenderInstruction;
import org.oscim.theme.renderinstruction.Symbol;
import org.oscim.theme.renderinstruction.Text;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@ -55,7 +54,7 @@ public class RenderThemeHandler extends DefaultHandler {
private static final String ELEMENT_NAME_RENDER_THEME = "rendertheme";
private static final String ELEMENT_NAME_RULE = "rule";
private static final String ELEMENT_NAME_STYPE_PATH_TEXT = "style-pathtext";
private static final String ELEMENT_NAME_STYLE_TEXT = "style-text";
private static final String ELEMENT_NAME_STYLE_AREA = "style-area";
private static final String ELEMENT_NAME_STYLE_LINE = "style-line";
private static final String ELEMENT_NAME_STYLE_OUTLINE = "style-outline";
@ -68,7 +67,8 @@ public class RenderThemeHandler extends DefaultHandler {
/**
* @param inputStream
* an input stream containing valid render theme XML data.
* @return a new RenderTheme which is created by parsing the XML data from the input stream.
* @return a new RenderTheme which is created by parsing the XML data from
* the input stream.
* @throws SAXException
* if an error occurs while parsing the render theme XML.
* @throws ParserConfigurationException
@ -171,11 +171,11 @@ public class RenderThemeHandler extends DefaultHandler {
mRuleStack.push(mCurrentRule);
}
else if (ELEMENT_NAME_STYPE_PATH_TEXT.equals(localName)) {
else if (ELEMENT_NAME_STYLE_TEXT.equals(localName)) {
checkState(localName, Element.STYLE);
PathText pathText = PathText.create(localName, attributes);
tmpStyleHash.put("t" + pathText.style, pathText);
// System.out.println("add style: " + pathText.style);
Text text = Text.create(localName, attributes, false);
tmpStyleHash.put("t" + text.style, text);
// System.out.println("add style: " + text.style);
}
else if (ELEMENT_NAME_STYLE_AREA.equals(localName)) {
@ -194,7 +194,8 @@ public class RenderThemeHandler extends DefaultHandler {
Line line = Line.create((Line) ri, localName, attributes, 0,
false);
tmpStyleHash.put("l" + line.style, line);
// System.out.println("add style: " + line.style + " from " + style);
// System.out.println("add style: " + line.style +
// " from " + style);
}
else {
Log.d("...", "this aint no style! " + style);
@ -222,8 +223,11 @@ public class RenderThemeHandler extends DefaultHandler {
else if ("caption".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
Caption caption = Caption.create(localName, attributes);
mCurrentRule.addRenderingInstruction(caption);
Text text = Text.create(localName, attributes, true);
mCurrentRule.addRenderingInstruction(text);
// Caption caption = Caption.create(localName, attributes);
// mCurrentRule.addRenderingInstruction(caption);
}
else if ("circle".equals(localName)) {
@ -244,10 +248,10 @@ public class RenderThemeHandler extends DefaultHandler {
mCurrentRule.addRenderingInstruction(lineSymbol);
}
else if ("pathText".equals(localName)) {
else if ("text".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
PathText pathText = PathText.create(localName, attributes);
mCurrentRule.addRenderingInstruction(pathText);
Text text = Text.create(localName, attributes, false);
mCurrentRule.addRenderingInstruction(text);
}
else if ("symbol".equals(localName)) {
@ -262,7 +266,8 @@ public class RenderThemeHandler extends DefaultHandler {
if (style != null) {
Line line = (Line) tmpStyleHash.get("l" + style);
if (line != null) {
// System.out.println("found style line : " + line.style);
// System.out.println("found style line : " +
// line.style);
Line newLine = Line.create(line, localName, attributes,
mLevel++, false);
@ -290,13 +295,13 @@ public class RenderThemeHandler extends DefaultHandler {
mCurrentRule.addRenderingInstruction(new AreaLevel(area,
mLevel++));
else
Log.d("...", "this aint no style inna di area! " + style);
Log.d("...", "this aint no style inna d'area! " + style);
}
} else if (ELEMENT_NAME_USE_STYLE_PATH_TEXT.equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
String style = attributes.getValue("name");
if (style != null) {
PathText pt = (PathText) tmpStyleHash.get("t" + style);
Text pt = (Text) tmpStyleHash.get("t" + style);
if (pt != null)
mCurrentRule.addRenderingInstruction(pt);
else

View File

@ -4,8 +4,8 @@
xsi:schemaLocation="http://mapsforge.org/renderTheme ../renderTheme.xsd"
version="1" map-background="#fcfcfa">
<style-pathtext name="road" k="name" font-size="16" fill="#101010" stroke="#ffffff" stroke-width="2.0" />
<style-pathtext name="major-road" k="name" font-style="bold" font-size="16" fill="#101010" stroke="#ffffff" stroke-width="2.0" />
<style-text name="road" k="name" font-size="16" fill="#101010" stroke="#ffffff" stroke-width="2.0" />
<style-text name="major-road" k="name" font-style="bold" font-size="16" fill="#101010" stroke="#ffffff" stroke-width="2.0" />
<style-area name="residential" fill="#f0eee8" fade="10"/>
@ -65,14 +65,14 @@
<style-line name="steps" stroke="#f1f0f4" width="0.25" cap="butt" />
<style-line name="water:outline" stroke="#a4bbcc" width="1.0" fixed="true" cap="butt" />
<style-line name="water" stroke="#b4cbdc" width="1.0" cap="butt" />
<style-line name="water" stroke="#afcbf3" width="1.0" cap="butt" />
<style-area name="water" fill="#afcbf3" />
<!-- no-go area boundary -->
<style-line name="fence" stroke="#444444" width="1.2" fixed="true" cap="butt"/>
<style-line name="aeroway:runway" stroke="#c8ccbe" width="1.8" cap="butt" />
<style-line name="building" stroke="#c9c3c1" width="1.2" fixed="true" cap="butt" fade="15"/>
<style-line name="building" stroke="#c9c3c1" width="1.0" fixed="true" cap="butt" fade="15"/>
<style-area name="building" fill="#e9e6e3" fade="15"/>
<!-- ways -->
@ -487,11 +487,11 @@
</rule>
<!-- outline 1 - 4 -->
<style-outline name="1" stroke="#ee605020" width="0.02"/>
<style-outline name="1" stroke="#aa807040" width="0.1"/>
<!-- <style-outline name="1" stroke="#404030"/> -->
<style-outline name="2" stroke="#c0c0c0" />
<style-outline name="primary" stroke="#7f7700" width="0.025"/>
<style-outline name="motorway" stroke="#805f2e" width="0.025"/>
<style-outline name="primary" stroke="#aa7f7700" width="0.1"/>
<style-outline name="motorway" stroke="#aa805f2e" width="0.1"/>
<!-- highway -->
@ -499,23 +499,23 @@
<rule e="way" k="*" v="*" zoom-min="5" zoom-max="10">
<rule e="way" k="area" v="~|no|false">
<rule e="way" k="*" v="secondary|primary_link" zoom-min="9">
<line stroke="#f2df6d" width="1.8" cap="butt" fixed="true" fade="9"/>
<line stroke="#f2df6d" width="1.3" cap="butt" fixed="true" fade="9"/>
</rule>
<rule e="way" k="*" v="trunk_link|motorway_link" zoom-min="8">
<line stroke="#fed6a3" width="1.8" cap="butt" fixed="true" fade="8"/>
<line stroke="#fed6a3" width="1.4" cap="butt" fixed="true" fade="8"/>
</rule>
<rule e="way" k="*" v="primary" zoom-min="5">
<line stroke="#f2df6d" width="1.8" cap="butt" fixed="true" fade="5"/>
<line stroke="#f2df6d" width="1.4" cap="butt" fixed="true" fade="5"/>
</rule>
<rule e="way" k="*" v="trunk" zoom-min="5">
<line stroke="#fed6a3" width="2.0" cap="butt" fixed="true" fade="5"/>
<line stroke="#fed6a3" width="1.4" cap="butt" fixed="true" fade="5"/>
</rule>
<rule e="way" k="*" v="motorway">
<line stroke="#eec693" width="2.2" cap="butt" fixed="true" fade="5"/>
<line stroke="#eec693" width="1.5" cap="butt" fixed="true" fade="5"/>
</rule>
</rule>
</rule>
@ -790,7 +790,7 @@
src="jar:/org/mapsforge/android/maps/rendertheme/osmarender/symbols/cable_car.png"
/> </rule> <rule e="way" k="aerialway" v="chair_lift"> <lineSymbol src="jar:/org/mapsforge/android/maps/rendertheme/osmarender/symbols/chair_lift_2.png"
/> </rule> <rule e="way" k="aerialway" v="gondola"> <lineSymbol src="jar:/org/mapsforge/android/maps/rendertheme/osmarender/symbols/gondola.png"
/> </rule> <rule e="way" k="*" v="*" zoom-min="14"> <pathText k="name" font-style="bold"
/> </rule> <rule e="way" k="*" v="*" zoom-min="14"> <text k="name" font-style="bold"
font-size="10" fill="#606060" stroke="#ffffff" width="2.0" /> </rule>
</rule> -->
@ -831,7 +831,7 @@
</rule>
<rule e="way" k="railway" v="rail|turntable" >
<line stroke="#887766" width="0.8" cap="butt" fixed="true" fade="12"/>
<line stroke="#ccaa9988" width="1.0" cap="butt" fixed="true" fade="12"/>
</rule>
<!-- <rule e="way" k="railway" v="rail" zoom-max="14" zoom-min="13">
<line stroke="#8888aa" width="0.6" cap="butt"
@ -969,6 +969,165 @@
stroke="#ffffff" stroke-width="2.0" /> -->
</rule>
</rule>
<!-- aeroway -->
<rule e="node" k="aeroway" v="*">
<rule e="node" k="aeroway" v="helipad" zoom-min="17">
<symbol src="jar:symbols/helipad.png" />
</rule>
<rule e="node" k="aeroway" v="aerodrome|airport" zoom-max="13">
<symbol src="jar:symbols/airport.png" />
</rule>
</rule>
<!-- amenity -->
<rule e="node" k="amenity" v="*">
<rule e="node" k="amenity" v="atm" zoom-min="17">
<symbol src="jar:symbols/atm.png" />
</rule>
<rule e="node" k="amenity" v="bank" zoom-min="17">
<symbol src="jar:symbols/bank.png" />
</rule>
<rule e="node" k="amenity" v="bench" zoom-min="17">
<symbol src="jar:symbols/bench.png" />
</rule>
<rule e="node" k="amenity" v="bicycle_rental" zoom-min="17">
<symbol src="jar:symbols/bicycle_rental.png" />
</rule>
<rule e="node" k="amenity" v="bus_station" zoom-min="17">
<symbol src="jar:symbols/bus_sta.png" />
</rule>
<rule e="node" k="amenity" v="cafe" zoom-min="17">
<symbol src="jar:symbols/cafe.png" />
</rule>
<rule e="node" k="amenity" v="cinema" zoom-min="17">
<symbol src="jar:symbols/cinema.png" />
</rule>
<rule e="node" k="amenity" v="drinking_water" zoom-min="17">
<symbol src="jar:symbols/drinking_water.png" />
</rule>
<rule e="node" k="amenity" v="fast_food" zoom-min="17">
<symbol src="jar:symbols/fastfood.png" />
</rule>
<rule e="node" k="amenity" v="fire_station" zoom-min="17">
<symbol src="jar:symbols/firebrigade.png" />
</rule>
<rule e="node" k="amenity" v="fountain" zoom-min="17">
<symbol src="jar:symbols/fountain.png" />
</rule>
<rule e="node" k="amenity" v="fuel" zoom-min="17">
<symbol src="jar:symbols/petrolStation.png" />
</rule>
<rule e="node" k="amenity" v="hospital" zoom-min="15">
<symbol src="jar:symbols/hospital.png" />
</rule>
<!-- <rule e="node" k="amenity" v="kindergarten" zoom-min="17">
<symbol src="jar:symbols/kindergarten.png" />
</rule>-->
<rule e="node" k="amenity" v="library" zoom-min="17">
<symbol src="jar:symbols/library.png" />
</rule>
<rule e="node" k="amenity" v="parking" zoom-min="17">
<symbol src="jar:symbols/parking.png" />
</rule>
<rule e="node" k="amenity" v="pharmacy" zoom-min="17">
<symbol src="jar:symbols/pharmacy.png" />
</rule>
<rule e="node" k="amenity" v="place_of_worship" zoom-min="17">
<rule e="node" k="denomination|religion" v="jewish">
<symbol src="jar:symbols/synagogue.png" />
</rule>
<rule e="node" k="denomination|religion" v="muslim|moslem">
<symbol src="jar:symbols/mosque.png" />
</rule>
<rule e="node" k="denomination|religion" v="christian">
<symbol src="jar:symbols/church.png" />
</rule>
</rule>
<rule e="node" k="amenity" v="post_box" zoom-min="17">
<symbol src="jar:symbols/postbox.png" />
</rule>
<rule e="node" k="amenity" v="post_office" zoom-min="17">
<symbol src="jar:symbols/postoffice.png" />
</rule>
<rule e="node" k="amenity" v="pub|bar" zoom-min="17">
<symbol src="jar:symbols/pub.png" />
</rule>
<!-- <rule e="node" k="amenity" v="recycling" zoom-min="17">
<symbol src="jar:symbols/recycling.png" />
</rule> -->
<rule e="node" k="amenity" v="restaurant" zoom-min="17">
<symbol src="jar:symbols/restaurant.png" />
</rule>
<rule e="node" k="amenity" v="school" zoom-min="17">
<symbol src="jar:symbols/school.png" />
</rule>
<rule e="node" k="amenity" v="shelter" zoom-min="17">
<symbol src="jar:symbols/shelter.png" />
</rule>
<!-- <rule e="node" k="amenity" v="telephone" zoom-min="17">
<symbol src="jar:symbols/telephone.png" />
</rule> -->
<rule e="node" k="amenity" v="theatre" zoom-min="17">
<symbol src="jar:symbols/theatre.png" />
</rule>
<rule e="node" k="amenity" v="toilets" zoom-min="17">
<symbol src="jar:symbols/toilets.png" />
</rule>
<rule e="node" k="amenity" v="university|college" zoom-min="17">
<symbol src="jar:symbols/university.png" />
</rule>
<!-- <rule e="node" k="*" v="*" zoom-min="17">
<caption k="name" font-style="bold" font-size="10" fill="#4040ff" stroke="#ffffff" stroke-width="2.0" />
</rule>-->
</rule>
<!-- shop -->
<rule e="node" k="shop" v="*">
<rule e="node" k="shop" v="bakery" zoom-min="17">
<symbol src="jar:symbols/bakery.png" />
</rule>
<rule e="node" k="shop" v="florist" zoom-min="17">
<symbol src="jar:symbols/florist.png" />
</rule>
<rule e="node" k="shop" v="supermarket|organic" zoom-min="17">
<symbol src="jar:symbols/supermarket.png" />
</rule>
<rule e="node" k="*" v="*" zoom-min="17">
<caption k="name" font-style="bold" font-size="10" fill="#4040ff" stroke="#ffffff" stroke-width="2.0" />
</rule>
</rule>
<!-- tourism -->
<rule e="node" k="tourism" v="*">
<rule e="node" k="tourism" v="alpine_hut" zoom-min="16">
<symbol src="jar:symbols/alpine_hut.png" />
</rule>
<rule e="node" k="tourism" v="camp_site" zoom-min="17">
<symbol src="jar:symbols/campSite.png" />
</rule>
<rule e="node" k="tourism" v="hostel" zoom-min="17">
<symbol src="jar:symbols/hostel.png" />
</rule>
<rule e="node" k="tourism" v="hotel" zoom-min="17">
<symbol src="jar:symbols/hotel.png" />
</rule>
<rule e="node" k="tourism" v="information" zoom-min="17">
<symbol src="jar:symbols/information.png" />
</rule>
<rule e="node" k="tourism" v="viewpoint" zoom-min="15">
<symbol src="jar:symbols/viewpoint.png" />
</rule>
<rule e="node" k="*" v="*" zoom-min="17">
<caption k="name" font-style="bold" font-size="10" fill="#4040ff" stroke="#ffffff" stroke-width="2.0" />
</rule>
</rule>
</rule>
</rendertheme>

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 742 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 B

Some files were not shown because too many files have changed in this diff Show More