switch to ShortBuffer for half-float, shader tweaks,..

This commit is contained in:
Hannes Janetzek
2012-06-20 17:24:38 +02:00
parent 5da8c6ed0d
commit f977fec1ae
12 changed files with 376 additions and 227 deletions

View File

@@ -125,7 +125,8 @@ public class MapView extends GLSurfaceView {
super(context, attributeSet); super(context, attributeSet);
if (!(context instanceof MapActivity)) { if (!(context instanceof MapActivity)) {
throw new IllegalArgumentException("context is not an instance of MapActivity"); throw new IllegalArgumentException(
"context is not an instance of MapActivity");
} }
setWillNotDraw(true); setWillNotDraw(true);
setWillNotCacheDrawing(true); setWillNotCacheDrawing(true);
@@ -138,7 +139,8 @@ public class MapView extends GLSurfaceView {
mMapController = new MapController(this); mMapController = new MapController(this);
// mMapDatabase = MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.POSTGIS_READER); // mMapDatabase = MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.POSTGIS_READER);
mMapDatabase = MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.MAP_READER); mMapDatabase = MapDatabaseFactory
.createMapDatabase(MapDatabaseInternal.MAP_READER);
mMapViewPosition = new MapViewPosition(this); mMapViewPosition = new MapViewPosition(this);
mMapScaleBar = new MapScaleBar(this); mMapScaleBar = new MapScaleBar(this);
@@ -327,7 +329,8 @@ public class MapView extends GLSurfaceView {
* the new center point of the map. * the new center point of the map.
*/ */
public void setCenter(GeoPoint geoPoint) { public void setCenter(GeoPoint geoPoint) {
MapPosition mapPosition = new MapPosition(geoPoint, mMapViewPosition.getZoomLevel(), 1); MapPosition mapPosition = new MapPosition(geoPoint,
mMapViewPosition.getZoomLevel(), 1);
setCenterAndZoom(mapPosition); setCenterAndZoom(mapPosition);
} }
@@ -566,16 +569,22 @@ public class MapView extends GLSurfaceView {
protected final void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { protected final void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// find out how big the zoom controls should be // find out how big the zoom controls should be
mMapZoomControls.measure( mMapZoomControls.measure(
MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.AT_MOST)); MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
MeasureSpec.AT_MOST));
// make sure that MapView is big enough to display the zoom controls // make sure that MapView is big enough to display the zoom controls
setMeasuredDimension(Math.max(MeasureSpec.getSize(widthMeasureSpec), mMapZoomControls.getMeasuredWidth()), setMeasuredDimension(
Math.max(MeasureSpec.getSize(heightMeasureSpec), mMapZoomControls.getMeasuredHeight())); Math.max(MeasureSpec.getSize(widthMeasureSpec),
mMapZoomControls.getMeasuredWidth()),
Math.max(MeasureSpec.getSize(heightMeasureSpec),
mMapZoomControls.getMeasuredHeight()));
} }
@Override @Override
protected synchronized void onSizeChanged(int width, int height, int oldWidth, int oldHeight) { protected synchronized void onSizeChanged(int width, int height, int oldWidth,
int oldHeight) {
mMapWorker.pause(); mMapWorker.pause();
mMapWorker.awaitPausing(); mMapWorker.awaitPausing();
super.onSizeChanged(width, height, oldWidth, oldHeight); super.onSizeChanged(width, height, oldWidth, oldHeight);
@@ -605,7 +614,8 @@ public class MapView extends GLSurfaceView {
* @return the maximum possible zoom level. * @return the maximum possible zoom level.
*/ */
byte getMaximumPossibleZoomLevel() { byte getMaximumPossibleZoomLevel() {
return (byte) Math.min(mMapZoomControls.getZoomLevelMax(), mMapGenerator.getZoomLevelMax()); return (byte) Math.min(mMapZoomControls.getZoomLevelMax(),
mMapGenerator.getZoomLevelMax());
} }
/** /**
@@ -615,8 +625,9 @@ public class MapView extends GLSurfaceView {
if (!mMapViewPosition.isValid()) { if (!mMapViewPosition.isValid()) {
return false; return false;
} else if (!mMapGenerator.requiresInternetConnection() } else if (!mMapGenerator.requiresInternetConnection()
&& (!mMapDatabase.hasOpenFile() || !mMapDatabase.getMapFileInfo().boundingBox.contains(getMapPosition() && (!mMapDatabase.hasOpenFile() || !mMapDatabase.getMapFileInfo().boundingBox
.getMapCenter()))) { .contains(getMapPosition()
.getMapCenter()))) {
return false; return false;
} }
@@ -624,7 +635,8 @@ public class MapView extends GLSurfaceView {
} }
byte limitZoomLevel(byte zoom) { byte limitZoomLevel(byte zoom) {
return (byte) Math.max(Math.min(zoom, getMaximumPossibleZoomLevel()), mMapZoomControls.getZoomLevelMin()); return (byte) Math.max(Math.min(zoom, getMaximumPossibleZoomLevel()),
mMapZoomControls.getZoomLevelMin());
} }
@Override @Override

View File

@@ -222,11 +222,13 @@ public class DatabaseRenderer implements MapGenerator, RenderCallback,
mWays = wayLength; mWays = wayLength;
if (!firstMatch && prevClosed == closed && !changed) { if (!firstMatch && prevClosed == closed && !changed) {
DatabaseRenderer.renderTheme.matchWay(this, tags, mCurrentTile.zoomLevel, DatabaseRenderer.renderTheme.matchWay(this, tags,
(byte) (mCurrentTile.zoomLevel + 0),
closed, false); closed, false);
} else { } else {
prevClosed = closed; prevClosed = closed;
DatabaseRenderer.renderTheme.matchWay(this, tags, mCurrentTile.zoomLevel, DatabaseRenderer.renderTheme.matchWay(this, tags,
(byte) (mCurrentTile.zoomLevel + 0),
closed, true); closed, true);
} }
@@ -268,6 +270,9 @@ public class DatabaseRenderer implements MapGenerator, RenderCallback,
@Override @Override
public void renderWay(Line line) { public void renderWay(Line line) {
// if (prevClosed && !mProjected)
// return;
projectToTile(false); projectToTile(false);
LineLayer outlineLayer = null; LineLayer outlineLayer = null;
@@ -304,7 +309,7 @@ public class DatabaseRenderer implements MapGenerator, RenderCallback,
if (!mDebugDrawPolygons) if (!mDebugDrawPolygons)
return; return;
// if (!projectToTile(mCurrentTile.zoomLevel < 13)) // if (!projectToTile(mCurrentTile.zoomLevel < 14))
if (!projectToTile(false)) if (!projectToTile(false))
return; return;

View File

@@ -17,6 +17,7 @@ package org.mapsforge.android.glrenderer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import android.util.SparseArray; import android.util.SparseArray;
@@ -56,7 +57,8 @@ class LineLayers {
} }
if (buf == null || buf.capacity() < size) { if (buf == null || buf.capacity() < size) {
ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 4).order(ByteOrder.nativeOrder()); ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 4).order(
ByteOrder.nativeOrder());
fbuf = bbuf.asFloatBuffer(); fbuf = bbuf.asFloatBuffer();
} else { } else {
fbuf.position(0); fbuf.position(0);
@@ -87,8 +89,8 @@ class LineLayers {
return fbuf; return fbuf;
} }
ByteBuffer compileLayerData(ByteBuffer buf) { ShortBuffer compileLayerData(ShortBuffer buf) {
ByteBuffer sbuf = buf; ShortBuffer sbuf = buf;
array = new LineLayer[layers.size()]; array = new LineLayer[layers.size()];
@@ -98,14 +100,16 @@ class LineLayers {
size += l.verticesCnt * NUM_VERTEX_FLOATS; size += l.verticesCnt * NUM_VERTEX_FLOATS;
} }
if (buf == null || buf.capacity() < size * 2) { if (buf == null || buf.capacity() < size) {
sbuf = ByteBuffer.allocateDirect(size * 2).order(ByteOrder.nativeOrder()); ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 2).order(
ByteOrder.nativeOrder());
sbuf = bbuf.asShortBuffer();
} else { } else {
sbuf.position(0); sbuf.position(0);
} }
int pos = 0; int pos = 0;
byte[] data = new byte[PoolItem.SIZE * 2]; short[] data = new short[PoolItem.SIZE];
for (int i = 0, n = array.length; i < n; i++) { for (int i = 0, n = array.length; i < n; i++) {
LineLayer l = array[i]; LineLayer l = array[i];
@@ -115,7 +119,7 @@ class LineLayers {
for (int k = 0, m = l.pool.size(); k < m; k++) { for (int k = 0, m = l.pool.size(); k < m; k++) {
PoolItem item = l.pool.get(k); PoolItem item = l.pool.get(k);
PoolItem.toHalfFloat(item, data); PoolItem.toHalfFloat(item, data);
sbuf.put(data, 0, item.used * 2); sbuf.put(data, 0, item.used);
} }
l.offset = pos; l.offset = pos;

View File

@@ -14,8 +14,8 @@
*/ */
package org.mapsforge.android.glrenderer; package org.mapsforge.android.glrenderer;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@@ -88,7 +88,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
private long mTileX, mTileY; private long mTileX, mTileY;
private FloatBuffer floatBuffer = null; private FloatBuffer floatBuffer = null;
private ByteBuffer byteBuffer = null; // private ByteBuffer byteBuffer = null;
private ShortBuffer shortBuffer = null;
boolean useHalfFloat = false; boolean useHalfFloat = false;
@@ -125,7 +126,6 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
private int gLineTexturePositionHandle; private int gLineTexturePositionHandle;
private int gLineColorHandle; private int gLineColorHandle;
private int gLineMatrixHandle; private int gLineMatrixHandle;
private int gLineWidthHandle;
private int gLineModeHandle; private int gLineModeHandle;
private int gPolygonProgram; private int gPolygonProgram;
@@ -325,7 +325,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
newTiles.tiles[tiles++] = tile; newTiles.tiles[tiles++] = tile;
if (!tile.isDrawn && !tile.isLoading) { if (!tile.isDrawn && !tile.isLoading) {
MapGeneratorJob job = new MapGeneratorJob(tile, mapGenerator, mJobParameter, mDebugSettings); MapGeneratorJob job = new MapGeneratorJob(tile, mapGenerator,
mJobParameter, mDebugSettings);
mJobList.add(job); mJobList.add(job);
} }
} }
@@ -395,8 +396,10 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
byte zoomLevel = mMapPosition.zoomLevel; byte zoomLevel = mMapPosition.zoomLevel;
float scale = mMapPosition.scale; float scale = mMapPosition.scale;
double x = MercatorProjection.longitudeToPixelX(mMapPosition.geoPoint.getLongitude(), zoomLevel); double x = MercatorProjection.longitudeToPixelX(
double y = MercatorProjection.latitudeToPixelY(mMapPosition.geoPoint.getLatitude(), zoomLevel); mMapPosition.geoPoint.getLongitude(), zoomLevel);
double y = MercatorProjection.latitudeToPixelY(
mMapPosition.geoPoint.getLatitude(), zoomLevel);
long tileX = MercatorProjection.pixelXToTileX(x, zoomLevel); long tileX = MercatorProjection.pixelXToTileX(x, zoomLevel);
long tileY = MercatorProjection.pixelYToTileY(y, zoomLevel); long tileY = MercatorProjection.pixelYToTileY(y, zoomLevel);
@@ -459,8 +462,10 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
blend = false; blend = false;
} }
GLES20.glUniform4f(gPolygonColorHandle, (color >> 16 & 0xff) / 255f * alpha, (color >> 8 & 0xff) / 255f GLES20.glUniform4f(gPolygonColorHandle,
* alpha, (color & 0xff) / 255f * alpha, alpha); (color >> 16 & 0xff) / 255f * alpha,
(color >> 8 & 0xff) / 255f * alpha,
(color & 0xff) / 255f * alpha, alpha);
// set stencil buffer mask used to draw this layer // set stencil buffer mask used to draw this layer
GLES20.glStencilFunc(GLES20.GL_EQUAL, 0xff, 1 << c); GLES20.glStencilFunc(GLES20.GL_EQUAL, 0xff, 1 << c);
@@ -486,10 +491,12 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.id); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.id);
if (useHalfFloat) { if (useHalfFloat) {
GLES20.glVertexAttribPointer(gPolygonVertexPositionHandle, 2, OES_HALF_FLOAT, false, 0, GLES20.glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
OES_HALF_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET); POLYGON_VERTICES_DATA_POS_OFFSET);
} else { } else {
GLES20.glVertexAttribPointer(gPolygonVertexPositionHandle, 2, GLES20.GL_FLOAT, false, 0, GLES20.glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
GLES20.GL_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET); POLYGON_VERTICES_DATA_POS_OFFSET);
} }
@@ -531,11 +538,11 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
else { else {
// clear stencilbuffer // clear stencilbuffer
GLES20.glStencilMask(0xFF); GLES20.glStencilMask(0xFF);
GLES20.glClear(GLES20.GL_STENCIL_BUFFER_BIT); // GLES20.glClear(GLES20.GL_STENCIL_BUFFER_BIT);
// clear stencilbuffer (tile region) // clear stencilbuffer (tile region)
// GLES20.glStencilOp(GLES20.GL_ZERO, GLES20.GL_ZERO, GLES20.GL_ZERO); GLES20.glStencilOp(GLES20.GL_ZERO, GLES20.GL_ZERO, GLES20.GL_ZERO);
// GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
} }
// stencil op for stencil method polygon drawing // stencil op for stencil method polygon drawing
@@ -554,7 +561,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
// modify alpha channel // modify alpha channel
float s = (mDrawScale < 1.3f ? 1.3f : mDrawScale); float s = (mDrawScale < 1.3f ? 1.3f : mDrawScale);
colors[cnt] = (colors[cnt] & 0xffffff) | (byte) ((s - 1) * 0xff) << 24; colors[cnt] = (colors[cnt] & 0xffffff)
| (byte) ((s - 1) * 0xff) << 24;
} }
} }
@@ -588,16 +596,20 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.id); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.id);
if (useHalfFloat) { if (useHalfFloat) {
GLES20.glVertexAttribPointer(gLineVertexPositionHandle, 2, OES_HALF_FLOAT, false, 8, GLES20.glVertexAttribPointer(gLineVertexPositionHandle, 2, OES_HALF_FLOAT,
false, 8,
LINE_VERTICES_DATA_POS_OFFSET); LINE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(gLineTexturePositionHandle, 2, OES_HALF_FLOAT, false, 8, GLES20.glVertexAttribPointer(gLineTexturePositionHandle, 2, OES_HALF_FLOAT,
false, 8,
LINE_VERTICES_DATA_TEX_OFFSET >> 1); LINE_VERTICES_DATA_TEX_OFFSET >> 1);
} else { } else {
GLES20.glVertexAttribPointer(gLineVertexPositionHandle, 2, GLES20.GL_FLOAT, false, 16, GLES20.glVertexAttribPointer(gLineVertexPositionHandle, 2, GLES20.GL_FLOAT,
false, 16,
LINE_VERTICES_DATA_POS_OFFSET); LINE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(gLineTexturePositionHandle, 2, GLES20.GL_FLOAT, false, 16, GLES20.glVertexAttribPointer(gLineTexturePositionHandle, 2, GLES20.GL_FLOAT,
false, 16,
LINE_VERTICES_DATA_TEX_OFFSET); LINE_VERTICES_DATA_TEX_OFFSET);
} }
@@ -629,6 +641,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
// linear scale for fixed lines // linear scale for fixed lines
float fdiv = 0.9f / (mDrawScale / z); float fdiv = 0.9f / (mDrawScale / z);
// int cnt = 0;
for (int i = 0, n = layers.length; i < n; i++) { for (int i = 0, n = layers.length; i < n; i++) {
LineLayer l = layers[i]; LineLayer l = layers[i];
@@ -637,14 +650,16 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
drawOutlines = l.isOutline; drawOutlines = l.isOutline;
drawFixed = l.isFixed; drawFixed = l.isFixed;
if (drawFixed) { if (drawFixed) {
GLES20.glUniform1i(gLineModeHandle, 2); GLES20.glUniform2f(gLineModeHandle, 0.4f, fdiv);
GLES20.glUniform1f(gLineWidthHandle, fdiv); // GLES20.glUniform1f(gLineWidthHandle, fdiv);
} else if (drawOutlines) { } else if (drawOutlines) {
GLES20.glUniform1i(gLineModeHandle, 1); GLES20.glUniform2f(gLineModeHandle, 0, wdiv);
GLES20.glUniform1f(gLineWidthHandle, wdiv); // GLES20.glUniform1i(gLineModeHandle, 1);
// GLES20.glUniform1f(gLineWidthHandle, wdiv);
} else { } else {
GLES20.glUniform1i(gLineModeHandle, 0); GLES20.glUniform2f(gLineModeHandle, 0, wdiv * 0.95f);
GLES20.glUniform1f(gLineWidthHandle, wdiv * 0.95f); // GLES20.glUniform1i(gLineModeHandle, 0);
// GLES20.glUniform1f(gLineWidthHandle, wdiv * 0.95f);
} }
} }
@@ -659,7 +674,12 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} else { } else {
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, l.offset, l.verticesCnt); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, l.offset, l.verticesCnt);
} }
// cnt += l.verticesCnt;
} }
// GLES20.glUniform2f(gLineModeHandle, 0, wdiv);
// float[] c = { 1, 0, 0, 1 };
// GLES20.glUniform4fv(gLineColorHandle, 1, c, 0);
// GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, cnt);
return true; return true;
} }
@@ -754,7 +774,15 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} }
} }
private int uploadCnt;
private boolean uploadTileData(GLMapTile tile) { private boolean uploadTileData(GLMapTile tile) {
// not sure about this, but seems it fixes some flickering when
// multiple tiles are uploaded in one go. but if this is really
// the issue tiles should stay corrupted..
if (uploadCnt++ > 0)
GLES20.glFinish();
if (tile.lineVBO == null) { if (tile.lineVBO == null) {
// Upload line data to vertex buffer object // Upload line data to vertex buffer object
synchronized (mVBOs) { synchronized (mVBOs) {
@@ -766,7 +794,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} }
} }
if (useHalfFloat) if (useHalfFloat)
byteBuffer = tile.lineLayers.compileLayerData(byteBuffer); shortBuffer = tile.lineLayers.compileLayerData(shortBuffer);
else else
floatBuffer = tile.lineLayers.compileLayerData(floatBuffer); floatBuffer = tile.lineLayers.compileLayerData(floatBuffer);
@@ -778,10 +806,12 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (useHalfFloat) { if (useHalfFloat) {
tile.lineVBO.size = tile.lineLayers.size * SHORT_BYTES; tile.lineVBO.size = tile.lineLayers.size * SHORT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.size, byteBuffer, GLES20.GL_STATIC_DRAW); GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.size,
shortBuffer, GLES20.GL_STATIC_DRAW);
} else { } else {
tile.lineVBO.size = tile.lineLayers.size * FLOAT_BYTES; tile.lineVBO.size = tile.lineLayers.size * FLOAT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.size, floatBuffer, GLES20.GL_STATIC_DRAW); GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.size,
floatBuffer, GLES20.GL_STATIC_DRAW);
} }
mBufferMemoryUsage += tile.lineVBO.size; mBufferMemoryUsage += tile.lineVBO.size;
@@ -791,7 +821,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} }
if (useHalfFloat) if (useHalfFloat)
byteBuffer = tile.polygonLayers.compileLayerData(byteBuffer); shortBuffer = tile.polygonLayers.compileLayerData(shortBuffer);
else else
floatBuffer = tile.polygonLayers.compileLayerData(floatBuffer); floatBuffer = tile.polygonLayers.compileLayerData(floatBuffer);
@@ -804,10 +834,12 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (useHalfFloat) { if (useHalfFloat) {
tile.polygonVBO.size = tile.polygonLayers.size * SHORT_BYTES; tile.polygonVBO.size = tile.polygonLayers.size * SHORT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.size, byteBuffer, GLES20.GL_STATIC_DRAW); GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.size,
shortBuffer, GLES20.GL_STATIC_DRAW);
} else { } else {
tile.polygonVBO.size = tile.polygonLayers.size * FLOAT_BYTES; tile.polygonVBO.size = tile.polygonLayers.size * FLOAT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.size, floatBuffer, GLES20.GL_STATIC_DRAW); GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.size,
floatBuffer, GLES20.GL_STATIC_DRAW);
} }
mBufferMemoryUsage += tile.polygonVBO.size; mBufferMemoryUsage += tile.polygonVBO.size;
@@ -835,7 +867,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
GLES20.glStencilMask(0xFF); GLES20.glStencilMask(0xFF);
GLES20.glDisable(GLES20.GL_SCISSOR_TEST); GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT);
GLES20.glFlush();
synchronized (this) { synchronized (this) {
mDrawX = mCurX; mDrawX = mCurX;
mDrawY = mCurY; mDrawY = mCurY;
@@ -854,14 +886,16 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
GLMapTile[] tiles = curTiles.tiles; GLMapTile[] tiles = curTiles.tiles;
if (mBufferMemoryUsage > LIMIT_BUFFERS) { if (mBufferMemoryUsage > LIMIT_BUFFERS) {
Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / (1024 * 1024) + "MB"); Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / (1024 * 1024)
+ "MB");
synchronized (mVBOs) { synchronized (mVBOs) {
for (VertexBufferObject vbo : mVBOs) { for (VertexBufferObject vbo : mVBOs) {
if (vbo.size == 0) if (vbo.size == 0)
continue; continue;
mBufferMemoryUsage -= vbo.size; mBufferMemoryUsage -= vbo.size;
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo.id); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo.id);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 0, null, GLES20.GL_STATIC_DRAW); GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 0, null,
GLES20.GL_STATIC_DRAW);
vbo.size = 0; vbo.size = 0;
} }
@@ -869,6 +903,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
Log.d(TAG, " > " + mBufferMemoryUsage / (1024 * 1024) + "MB"); Log.d(TAG, " > " + mBufferMemoryUsage / (1024 * 1024) + "MB");
} }
uploadCnt = 0;
// check visible tiles, set tile clip scissors, upload new vertex data // check visible tiles, set tile clip scissors, upload new vertex data
for (int i = 0; i < tileCnt; i++) { for (int i = 0; i < tileCnt; i++) {
GLMapTile tile = tiles[i]; GLMapTile tile = tiles[i];
@@ -880,7 +916,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
uploadTileData(tile); uploadTileData(tile);
if (timing) if (timing)
Log.d(TAG, "buffer upload took: " + (SystemClock.uptimeMillis() - start)); Log.d(TAG, "buffer upload took: "
+ (SystemClock.uptimeMillis() - start));
continue; continue;
} }
@@ -901,6 +938,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} }
} }
} }
// GLES20.glFinish();
if (timing) if (timing)
clear_time = (SystemClock.uptimeMillis() - start); clear_time = (SystemClock.uptimeMillis() - start);
@@ -930,7 +968,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
GLES20.glFinish(); GLES20.glFinish();
poly_time = (SystemClock.uptimeMillis() - start); poly_time = (SystemClock.uptimeMillis() - start);
} }
// GLES20.glFlush();
// Draw lines // Draw lines
GLES20.glEnable(GLES20.GL_BLEND); GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glUseProgram(gLineProgram); GLES20.glUseProgram(gLineProgram);
@@ -946,11 +984,12 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} }
} }
// GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
if (timing) { if (timing) {
GLES20.glFinish(); GLES20.glFinish();
Log.d(TAG, "draw took " + (SystemClock.uptimeMillis() - start) + " " + clear_time + " " + poly_time); Log.d(TAG, "draw took " + (SystemClock.uptimeMillis() - start) + " "
+ clear_time + " " + poly_time);
} }
} }
@@ -1002,10 +1041,12 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
public void onSurfaceCreated(GL10 gl, EGLConfig config) { public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Set up the program for rendering lines // Set up the program for rendering lines
gLineProgram = GlUtils.createProgram(Shaders.gLineVertexShader, Shaders.gLineFragmentShader); gLineProgram = GlUtils.createProgram(Shaders.gLineVertexShader,
Shaders.gLineFragmentShader);
if (gLineProgram == 0) { if (gLineProgram == 0) {
Log.e(TAG, "trying simple line program."); Log.e(TAG, "trying simple line program.");
gLineProgram = GlUtils.createProgram(Shaders.gLineVertexShader, Shaders.gLineFragmentShaderSimple); gLineProgram = GlUtils.createProgram(Shaders.gLineVertexShader,
Shaders.gLineFragmentShaderSimple);
if (gLineProgram == 0) { if (gLineProgram == 0) {
Log.e(TAG, "Could not create line program."); Log.e(TAG, "Could not create line program.");
return; return;
@@ -1020,20 +1061,22 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
Log.d(TAG, "Extensions: " + ext); Log.d(TAG, "Extensions: " + ext);
gLineMatrixHandle = GLES20.glGetUniformLocation(gLineProgram, "u_center"); gLineMatrixHandle = GLES20.glGetUniformLocation(gLineProgram, "u_center");
gLineWidthHandle = GLES20.glGetUniformLocation(gLineProgram, "u_width");
gLineModeHandle = GLES20.glGetUniformLocation(gLineProgram, "u_mode"); gLineModeHandle = GLES20.glGetUniformLocation(gLineProgram, "u_mode");
gLineColorHandle = GLES20.glGetUniformLocation(gLineProgram, "u_color"); gLineColorHandle = GLES20.glGetUniformLocation(gLineProgram, "u_color");
gLineVertexPositionHandle = GLES20.glGetAttribLocation(gLineProgram, "a_position"); gLineVertexPositionHandle = GLES20
.glGetAttribLocation(gLineProgram, "a_position");
gLineTexturePositionHandle = GLES20.glGetAttribLocation(gLineProgram, "a_st"); gLineTexturePositionHandle = GLES20.glGetAttribLocation(gLineProgram, "a_st");
// Set up the program for rendering polygons // Set up the program for rendering polygons
gPolygonProgram = GlUtils.createProgram(Shaders.gPolygonVertexShader, Shaders.gPolygonFragmentShader); gPolygonProgram = GlUtils.createProgram(Shaders.gPolygonVertexShader,
Shaders.gPolygonFragmentShader);
if (gPolygonProgram == 0) { if (gPolygonProgram == 0) {
Log.e(TAG, "Could not create polygon program."); Log.e(TAG, "Could not create polygon program.");
return; return;
} }
gPolygonMatrixHandle = GLES20.glGetUniformLocation(gPolygonProgram, "u_center"); gPolygonMatrixHandle = GLES20.glGetUniformLocation(gPolygonProgram, "u_center");
gPolygonVertexPositionHandle = GLES20.glGetAttribLocation(gPolygonProgram, "a_position"); gPolygonVertexPositionHandle = GLES20.glGetAttribLocation(gPolygonProgram,
"a_position");
gPolygonColorHandle = GLES20.glGetUniformLocation(gPolygonProgram, "u_color"); gPolygonColorHandle = GLES20.glGetUniformLocation(gPolygonProgram, "u_color");
GLES20.glUseProgram(gPolygonProgram); GLES20.glUseProgram(gPolygonProgram);

View File

@@ -16,11 +16,14 @@ package org.mapsforge.android.glrenderer;
import java.util.LinkedList; import java.util.LinkedList;
import org.mapsforge.core.Tile;
class PolygonLayer extends Layer { class PolygonLayer extends Layer {
int fadeLevel; int fadeLevel;
private boolean first = true;
private float originX; // private boolean first = true;
private float originY; // private float originX;
// private float originY;
PolygonLayer(int layer, int color, int fade) { PolygonLayer(int layer, int color, int fade) {
super(layer, color); super(layer, color);
@@ -34,11 +37,11 @@ class PolygonLayer extends Layer {
verticesCnt += length / 2 + 2; verticesCnt += length / 2 + 2;
if (first) { // if (first) {
first = false; // first = false;
originX = points[pos]; // originX = points[pos];
originY = points[pos + 1]; // originY = points[pos + 1];
} // }
float[] curVertices = curItem.vertices; float[] curVertices = curItem.vertices;
int outPos = curItem.used; int outPos = curItem.used;
@@ -48,8 +51,8 @@ class PolygonLayer extends Layer {
outPos = 0; outPos = 0;
} }
curVertices[outPos++] = originX; curVertices[outPos++] = Tile.TILE_SIZE >> 1;
curVertices[outPos++] = originY; curVertices[outPos++] = Tile.TILE_SIZE >> 1;
int remaining = length; int remaining = length;
int inPos = pos; int inPos = pos;
@@ -74,7 +77,7 @@ class PolygonLayer extends Layer {
curVertices = getNextItem(); curVertices = getNextItem();
outPos = 0; outPos = 0;
} }
// Float.intBitsToFloat(bits)
curVertices[outPos++] = points[pos + 0]; curVertices[outPos++] = points[pos + 0];
curVertices[outPos++] = points[pos + 1]; curVertices[outPos++] = points[pos + 1];

View File

@@ -17,6 +17,7 @@ package org.mapsforge.android.glrenderer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.mapsforge.android.utils.FastMath; import org.mapsforge.android.utils.FastMath;
import org.mapsforge.core.Tile; import org.mapsforge.core.Tile;
@@ -25,10 +26,11 @@ import android.util.SparseArray;
class PolygonLayers { class PolygonLayers {
private static final int NUM_VERTEX_FLOATS = 2; private static final int NUM_VERTEX_FLOATS = 2;
private static final float[] mFillCoords = { -2, Tile.TILE_SIZE + 1, Tile.TILE_SIZE + 1, Tile.TILE_SIZE + 1, -2, private static final float[] mFillCoords = { -2, Tile.TILE_SIZE + 1,
Tile.TILE_SIZE + 1, Tile.TILE_SIZE + 1, -2,
-2, Tile.TILE_SIZE + 1, -2 }; -2, Tile.TILE_SIZE + 1, -2 };
private static byte[] mByteFillCoords = null; private static short[] mByteFillCoords = null;
private SparseArray<PolygonLayer> layers; private SparseArray<PolygonLayer> layers;
@@ -68,7 +70,8 @@ class PolygonLayers {
size *= NUM_VERTEX_FLOATS; size *= NUM_VERTEX_FLOATS;
if (buf == null || buf.capacity() < size) { if (buf == null || buf.capacity() < size) {
ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 4).order(ByteOrder.nativeOrder()); ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 4).order(
ByteOrder.nativeOrder());
// Log.d("GLMap", "allocate buffer " + size); // Log.d("GLMap", "allocate buffer " + size);
fbuf = bbuf.asFloatBuffer(); fbuf = bbuf.asFloatBuffer();
} else { } else {
@@ -100,8 +103,8 @@ class PolygonLayers {
return fbuf; return fbuf;
} }
ByteBuffer compileLayerData(ByteBuffer buf) { ShortBuffer compileLayerData(ShortBuffer buf) {
ByteBuffer bbuf = buf; ShortBuffer sbuf = buf;
array = new PolygonLayer[layers.size()]; array = new PolygonLayer[layers.size()];
@@ -113,27 +116,29 @@ class PolygonLayers {
size *= NUM_VERTEX_FLOATS; size *= NUM_VERTEX_FLOATS;
if (buf == null || buf.capacity() < size * 2) { if (buf == null || buf.capacity() < size) {
bbuf = ByteBuffer.allocateDirect(size * 2).order(ByteOrder.nativeOrder()); ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 2).order(
ByteOrder.nativeOrder());
sbuf = bbuf.asShortBuffer();
} else { } else {
bbuf.position(0); sbuf.position(0);
} }
byte[] data = new byte[PoolItem.SIZE * 2]; short[] data = new short[PoolItem.SIZE];
if (mByteFillCoords == null) { if (mByteFillCoords == null) {
mByteFillCoords = new byte[16]; mByteFillCoords = new short[8];
FastMath.convertFloatToHalf(mFillCoords[0], mByteFillCoords, 0); FastMath.convertFloatToHalf(mFillCoords[0], mByteFillCoords, 0);
FastMath.convertFloatToHalf(mFillCoords[1], mByteFillCoords, 2); FastMath.convertFloatToHalf(mFillCoords[1], mByteFillCoords, 1);
FastMath.convertFloatToHalf(mFillCoords[2], mByteFillCoords, 4); FastMath.convertFloatToHalf(mFillCoords[2], mByteFillCoords, 2);
FastMath.convertFloatToHalf(mFillCoords[3], mByteFillCoords, 6); FastMath.convertFloatToHalf(mFillCoords[3], mByteFillCoords, 3);
FastMath.convertFloatToHalf(mFillCoords[4], mByteFillCoords, 8); FastMath.convertFloatToHalf(mFillCoords[4], mByteFillCoords, 4);
FastMath.convertFloatToHalf(mFillCoords[5], mByteFillCoords, 10); FastMath.convertFloatToHalf(mFillCoords[5], mByteFillCoords, 5);
FastMath.convertFloatToHalf(mFillCoords[6], mByteFillCoords, 12); FastMath.convertFloatToHalf(mFillCoords[6], mByteFillCoords, 6);
FastMath.convertFloatToHalf(mFillCoords[7], mByteFillCoords, 14); FastMath.convertFloatToHalf(mFillCoords[7], mByteFillCoords, 7);
} }
bbuf.put(mByteFillCoords, 0, 16); sbuf.put(mByteFillCoords, 0, 8);
int pos = 4; int pos = 4;
for (int i = 0, n = array.length; i < n; i++) { for (int i = 0, n = array.length; i < n; i++) {
@@ -142,7 +147,7 @@ class PolygonLayers {
for (int k = 0, m = l.pool.size(); k < m; k++) { for (int k = 0, m = l.pool.size(); k < m; k++) {
PoolItem item = l.pool.get(k); PoolItem item = l.pool.get(k);
PoolItem.toHalfFloat(item, data); PoolItem.toHalfFloat(item, data);
bbuf.put(data, 0, item.used * 2); sbuf.put(data, 0, item.used);
} }
l.offset = pos; l.offset = pos;
@@ -152,11 +157,11 @@ class PolygonLayers {
l.pool = null; l.pool = null;
} }
bbuf.position(0); sbuf.position(0);
// not needed for drawing // not needed for drawing
layers = null; layers = null;
return bbuf; return sbuf;
} }
} }

View File

@@ -15,74 +15,79 @@
package org.mapsforge.android.glrenderer; package org.mapsforge.android.glrenderer;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
// TODO use byte[] for half-float, not converting on compilation (in glThread) // TODO use byte[] for half-float, not converting on compilation (in glThread)
class PoolItem { class PoolItem {
final float[] vertices; final float[] vertices;
// final byte[] vertices;
int used; int used;
PoolItem() { PoolItem() {
vertices = new float[SIZE]; vertices = new float[SIZE];
// vertices = new byte[SIZE];
used = 0; used = 0;
} }
static int SIZE = 256; static int SIZE = 256;
private static final byte b0x7c = (byte) 0x7c;
private static final byte b0x00 = (byte) 0x00;
private static final byte b0x01 = (byte) 0x01;
private static final byte b0xfc = (byte) 0xfc;
private static final byte b0x80 = (byte) 0x80;
private static final byte b0x7b = (byte) 0x7b;
private static final byte b0xff = (byte) 0xff;
private static final byte b0xfb = (byte) 0xfb;
private static final float FLOAT_HALF_PREC = 5.96046E-8f; private static final float FLOAT_HALF_PREC = 5.96046E-8f;
private static final float FLOAT_HALF_MAX = 65504f; private static final float FLOAT_HALF_MAX = 65504f;
static void toHalfFloat(PoolItem item, byte[] data) { private static ByteBuffer byteBuffer = ByteBuffer.allocate(SIZE * 4);
private static IntBuffer intBuffer = byteBuffer.asIntBuffer();
private static FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
private static int[] intArray = new int[SIZE];
static void toHalfFloat(PoolItem item, short[] data) {
floatBuffer.position(0);
floatBuffer.put(item.vertices, 0, item.used);
intBuffer.position(0);
intBuffer.get(intArray, 0, item.used);
int out = 0; int out = 0;
for (int j = 0; j < item.used; j++) { for (int j = 0; j < item.used; j++) {
float flt = item.vertices[j]; float flt = item.vertices[j];
int f = intArray[j];
if (flt == 0f) { if (f == 0x0000000) {
data[out++] = b0x00; // == 0
data[out++] = b0x00; data[out++] = (short) 0x0000;
} else if (flt == -0f) { } else if (f == 0x80000000) {
data[out++] = b0x00; // == -0
data[out++] = b0x80; data[out++] = (short) 0x8000;
} else if (f == 0x3f800000) {
// == 1
data[out++] = (short) 0x3c00;
} else if (f == 0xbf800000) {
// == -1
data[out++] = (short) 0xbc00;
} else if (flt > FLOAT_HALF_MAX) { } else if (flt > FLOAT_HALF_MAX) {
if (flt == Float.POSITIVE_INFINITY) { if (flt == Float.POSITIVE_INFINITY) {
data[out++] = b0x00; data[out++] = (short) 0x7c00;
data[out++] = b0x7c;
} else { } else {
data[out++] = b0xff; data[out++] = (short) 0x7bff;
data[out++] = b0x7b;
} }
} else if (flt < -FLOAT_HALF_MAX) { } else if (flt < -FLOAT_HALF_MAX) {
if (flt == Float.NEGATIVE_INFINITY) { if (flt == Float.NEGATIVE_INFINITY) {
data[out++] = b0x00; data[out++] = (short) 0xfc00;
data[out++] = b0xfc;
} else { } else {
data[out++] = b0xff; data[out++] = (short) 0xfbff;
data[out++] = b0xfb;
} }
} else if (flt > 0f && flt < FLOAT_HALF_PREC) { } else if (flt > 0f && flt < FLOAT_HALF_PREC) {
data[out++] = b0x01; data[out++] = (short) 0x0001;
data[out++] = b0x00;
} else if (flt < 0f && flt > -FLOAT_HALF_PREC) { } else if (flt < 0f && flt > -FLOAT_HALF_PREC) {
data[out++] = b0x01; data[out++] = (short) 0x8001;
data[out++] = b0x80;
} else { } else {
int f = Float.floatToIntBits(flt); // maybe just ignore and set 0? -- we'll see. when this happens
if (f == 0x7fc00000) if (f == 0x7fc00000)
throw new UnsupportedOperationException("NaN to half conversion not supported!"); throw new UnsupportedOperationException(
"NaN to half conversion not supported!");
data[out++] = (byte) ((f >> 13) & 0xff); data[out++] = (short) (((f >> 16) & 0x8000)
| ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00)
data[out++] = (byte) (((f >> 24) & 0x80) | ((((f & 0x7f800000) - 0x38000000) >> 21) & 0x7c) | ((f >> 21) & 0x03)); | ((f >> 13) & 0x03ff));
} }
} }
} }

View File

@@ -17,60 +17,78 @@ package org.mapsforge.android.glrenderer;
class Shaders { class Shaders {
final static String gLineVertexShader = "" final static String gLineVertexShader = ""
+ "precision highp float; \n" + "precision mediump float; \n"
+ "uniform mat4 u_center;" + "uniform mat4 u_center;"
+ "uniform float u_width;" // + "uniform float u_width;"
+ "attribute vec4 a_position;" + "attribute vec4 a_position;"
+ "attribute vec2 a_st;" + "attribute vec2 a_st;"
+ "varying vec2 v_st;" + "varying vec2 v_st;"
+ "void main() {" + "void main() {"
+ " gl_Position = u_center * a_position;" + " gl_Position = u_center * a_position;"
+ " v_st = a_st;" + "}"; + " v_st = a_st;"
+ "}";
final static String gLineFragmentShader = "" final static String gLineFragmentShader = ""
+ "#extension GL_OES_standard_derivatives : enable\n" + "#extension GL_OES_standard_derivatives : enable\n"
+ "precision mediump float;" + "precision mediump float;"
+ "uniform float u_width;" + "uniform vec2 u_mode;"
+ "uniform int u_mode;"
+ "uniform vec4 u_color;" + "uniform vec4 u_color;"
+ "const float zero = 0.0;" + "const float zero = 0.0;"
+ "const int standard = 0;"
+ "const int fixed_width = 2;"
+ "const vec4 blank = vec4(1.0, 0.0, 0.0, 1.0);"
+ "const vec4 blank2 = vec4(0.0, 1.0, 0.0, 1.0);"
+ "varying vec2 v_st;" + "varying vec2 v_st;"
+ "void main() {" + "void main() {"
+ " if (u_mode != fixed_width) {" + "float width = u_mode[1];"
// + " gl_FragColor = u_color;" // + " if (v_st.t == zero){ "
// + " float fuzz;" // + " float fuzz = fwidth(v_st.s) * 1.5;"
// + " float len;" // + " gl_FragColor = u_color * smoothstep(-fuzz * u_mode[0], fuzz, width - abs(v_st.s));"
+ " if (v_st.t == zero){ " // + " } else {"
// + " fuzz = - sqrt(dFdx(v_st.s) * dFdx(v_st.s) + dFdy(v_st.s) * dFdy(v_st.s));" + " float fuzz = max(fwidth(v_st.s), fwidth(v_st.t)) * 1.5;"
+ " float fuzz = -fwidth(v_st.s) * 1.5;" + " gl_FragColor = u_color * smoothstep(-fuzz * u_mode[0], fuzz, width - length(v_st));"
+ " float len = abs(v_st.s) - u_width;" // + " } "
// + " if (len < fuzz)"
+ " gl_FragColor = u_color * smoothstep(zero, fuzz, len);"
+ " } else {"
+ " float fuzz = -max(fwidth(v_st.s), fwidth(v_st.t)) * 1.5;"
+ " float len = length(v_st) - u_width;"
// + " if (len < fuzz)"
+ " gl_FragColor = u_color * smoothstep(zero, fuzz, len);"
+ " } "
// + " if (len > zero)"
// + " gl_FragColor = blank;"
// + " discard;"
// + " gl_FragColor = u_color;"
// + " else if (len < fuzz)"
// + " gl_FragColor = blank2;"
// + " else "
+ " } else { "
+ " float fuzz = fwidth(v_st.s);"
// + " gl_FragColor = u_color * smoothstep(fuzz, zero, abs(v_st.s) - u_width + fuzz);"
// + " fuzz = - sqrt(dFdx(v_st.s) * dFdx(v_st.s) + dFdy(v_st.s) * dFdy(v_st.s)) * 1.5;"
+ " gl_FragColor = u_color * smoothstep(fuzz*0.5, -fuzz, abs(v_st.s) - u_width);"
+ " }"
+ "}"; + "}";
// final static String gLineFragmentShader = ""
// + "#extension GL_OES_standard_derivatives : enable\n"
// + "precision mediump float;"
// + "uniform float u_width;"
// + "uniform vec2 u_mode;"
// + "uniform vec4 u_color;"
// + "const float zero = 0.0;"
// // + "const vec4 blank = vec4(1.0, 0.0, 0.0, 1.0);"
// + "varying vec2 v_st;"
// + "void main() {"
// + "float width = u_mode[1];"
// // + "float alpha = 1.0;"
// + " if (u_mode[0] == zero) {"
// // + " gl_FragColor = u_color;"
// // + " float fuzz;"
// // + " float len;"
// + " if (v_st.t == zero){ "
// // + " fuzz = - sqrt(dFdx(v_st.s) * dFdx(v_st.s) + dFdy(v_st.s) * dFdy(v_st.s));"
// + " float fuzz = -fwidth(v_st.s) * 1.5;"
// + " float len = abs(v_st.s) - width;"
// // + " if (len < fuzz)"
// + " gl_FragColor = u_color * smoothstep(zero, fuzz, len);"
// + " } else {"
// + " float fuzz = -max(fwidth(v_st.s), fwidth(v_st.t)) * 1.5;"
// + " float len = length(v_st) - width;"
// // + " if (len < fuzz)"
// + " gl_FragColor = u_color * smoothstep(zero, fuzz, len);"
// + " } "
// // + " if (len > zero)"
// // + " gl_FragColor = blank;"
// // + " discard;"
// // + " gl_FragColor = u_color;"
// // + " else if (len < fuzz)"
// // + " gl_FragColor = blank2;"
// // + " else "
// + " } else { "
// + " float fuzz = fwidth(v_st.s);"
// // + " gl_FragColor = u_color * smoothstep(fuzz, zero, abs(v_st.s) - u_width + fuzz);"
// // + " fuzz = - sqrt(dFdx(v_st.s) * dFdx(v_st.s) + dFdy(v_st.s) * dFdy(v_st.s)) * 1.5;"
// + " gl_FragColor = u_color * smoothstep(fuzz*0.5, -fuzz, abs(v_st.s) - width);"
// + " }"
// + "}";
// final static String gLineFragmentShader = "" + // final static String gLineFragmentShader = "" +
// "#extension GL_OES_standard_derivatives : enable\n" + // "#extension GL_OES_standard_derivatives : enable\n" +
// "precision mediump float;" + // "precision mediump float;" +

View File

@@ -208,7 +208,7 @@
<rule e="way" k="waterway" v="*"> <rule e="way" k="waterway" v="*">
<rule e="way" k="waterway" v="ditch|drain" zoom-min="14"> <rule e="way" k="waterway" v="ditch|drain" zoom-min="14">
<line stroke="#b4cbdc" stroke-width="0.5" stroke-linecap="butt" <line stroke="#b4cbdc" stroke-width="0.7" stroke-linecap="butt"
fixed="true" /> fixed="true" />
</rule> </rule>
@@ -332,7 +332,7 @@
<rule e="way" k="outline" v="*"> <rule e="way" k="outline" v="*">
<rule e="way" k="*" v="1"> <rule e="way" k="*" v="1">
<outline stroke="#909090" /> <outline stroke="#bb909090" />
</rule> </rule>
<rule e="way" k="*" v="2"> <rule e="way" k="*" v="2">
<outline stroke="#c0c0c0" /> <outline stroke="#c0c0c0" />
@@ -401,14 +401,10 @@
<line stroke="#d3cb98" stroke-width="0.4" outline="2" /> <line stroke="#d3cb98" stroke-width="0.4" outline="2" />
</rule> </rule>
<rule e="way" k="*" v="service|byway"> <rule e="way" k="*" v="service|byway|pedestrian">
<line stroke="#ffffff" stroke-width="0.8" outline="1" /> <line stroke="#ffffff" stroke-width="0.8" outline="1" />
</rule> </rule>
<rule e="way" k="*" v="pedestrian">
<line stroke="#f1f0f4" stroke-width="0.8" outline="1" />
</rule>
<rule e="way" k="*" v="construction"> <rule e="way" k="*" v="construction">
<line stroke="#d0d0d0" stroke-width="1.3" outline="1" /> <line stroke="#d0d0d0" stroke-width="1.3" outline="1" />
</rule> </rule>
@@ -418,9 +414,7 @@
<rule e="way" k="*" v="residential|road|unclassified|living_street"> <rule e="way" k="*" v="residential|road|unclassified|living_street">
<rule e="way" k="bridge" v="yes|true"> <rule e="way" k="bridge" v="yes|true">
<line stroke="#ffffff" stroke-width="1.3" stroke-linecap="butt" <line stroke="#ffffff" stroke-width="1.3" outline="2" stroke-linecap="butt" />
outline="2" />
</rule> </rule>
<rule e="way" k="bridge" v="~|no|false"> <rule e="way" k="bridge" v="~|no|false">
<line stroke="#ffffff" stroke-width="1.3" outline="1" /> <line stroke="#ffffff" stroke-width="1.3" outline="1" />
@@ -434,19 +428,17 @@
<rule e="way" k="*" v="*" zoom-min="11"> <rule e="way" k="*" v="*" zoom-min="11">
<rule e="way" k="*" v="tertiary|secondary_link"> <rule e="way" k="*" v="tertiary|secondary_link">
<line stroke="#ffff9a" stroke-width="1.5" outline="3" /> <line stroke="#ffffff" stroke-width="1.5" outline="1" />
</rule> </rule>
<rule e="way" k="*" v="trunk_link|motorway_link"> <rule e="way" k="*" v="trunk_link|motorway_link">
<line stroke="#fed6a3" stroke-width="1.6" stroke-linecap="butt" <line stroke="#fed6a3" stroke-width="1.5" outline="4" stroke-linecap="butt" />
outline="4" />
</rule> </rule>
<rule e="way" k="*" v="secondary|primary_link"> <rule e="way" k="*" v="secondary|primary_link">
<rule e="way" k="bridge" v="yes|true"> <rule e="way" k="bridge" v="yes|true">
<line stroke="#fefe8a" stroke-width="1.6" outline="1" <line stroke="#fefe8a" stroke-width="1.6" outline="1" stroke-linecap="butt" />
stroke-linecap="butt" />
</rule> </rule>
<rule e="way" k="bridge" v="~|no|false"> <rule e="way" k="bridge" v="~|no|false">
@@ -455,18 +447,15 @@
</rule> </rule>
<rule e="way" k="*" v="primary"> <rule e="way" k="*" v="primary">
<line stroke="#fefe8a" stroke-width="1.7" stroke-linecap="butt" <line stroke="#fefe8a" stroke-width="1.7" outline="3" stroke-linecap="butt" />
outline="3" />
</rule> </rule>
<rule e="way" k="*" v="trunk"> <rule e="way" k="*" v="trunk">
<line stroke="#fed6a3" stroke-width="1.8" stroke-linecap="butt" <line stroke="#fed6a3" stroke-width="1.8" outline="4" stroke-linecap="butt" />
outline="4" />
</rule> </rule>
<rule e="way" k="*" v="motorway"> <rule e="way" k="*" v="motorway">
<line stroke="#eec693" stroke-width="1.9" stroke-linecap="butt" <line stroke="#eec693" stroke-width="1.9" outline="4" stroke-linecap="butt" />
outline="4" />
</rule> </rule>
</rule> </rule>
</rule> </rule>

View File

@@ -1,8 +1,7 @@
package org.mapsforge.android.utils; package org.mapsforge.android.utils;
/** /**
* Copyright (c) 2009-2010 jMonkeyEngine * Copyright (c) 2009-2010 jMonkeyEngine All rights reserved. FastMath.java
* All rights reserved. FastMath.java
*/ */
public class FastMath { public class FastMath {
@@ -58,7 +57,8 @@ public class FastMath {
int f = Float.floatToIntBits(flt); int f = Float.floatToIntBits(flt);
if (f == 0x7fc00000) if (f == 0x7fc00000)
throw new UnsupportedOperationException("NaN to half conversion not supported!"); throw new UnsupportedOperationException(
"NaN to half conversion not supported!");
data[pos + 1] = (byte) (((f >> 24) & 0x80) data[pos + 1] = (byte) (((f >> 24) & 0x80)
| ((((f & 0x7f800000) - 0x38000000) >> 21) & 0x7c) | ((((f & 0x7f800000) - 0x38000000) >> 21) & 0x7c)
@@ -67,4 +67,50 @@ public class FastMath {
data[pos + 0] = (byte) ((f >> 13) & 0xff); data[pos + 0] = (byte) ((f >> 13) & 0xff);
} }
} }
/**
* @param flt
* ...
* @param data
* ...
* @param pos
* ..
*/
public static void convertFloatToHalf(float flt, short[] data, int pos) {
if (flt == 0f) {
data[pos] = (short) 0x0000;
} else if (flt == -0f) {
data[pos] = (short) 0x8000;
} else if (flt == 1f) {
data[pos] = (short) 0x3c00;
} else if (flt == -1f) {
data[pos] = (short) 0xbc00;
} else if (flt > FLOAT_HALF_MAX) {
if (flt == Float.POSITIVE_INFINITY) {
data[pos] = (short) 0x7c00;
} else {
data[pos] = (short) 0x7bff;
}
} else if (flt < -FLOAT_HALF_MAX) {
if (flt == Float.NEGATIVE_INFINITY) {
data[pos] = (short) 0xfc00;
} else {
data[pos] = (short) 0xfbff;
}
} else if (flt > 0f && flt < FLOAT_HALF_PREC) {
data[pos] = (short) 0x0001;
} else if (flt < 0f && flt > -FLOAT_HALF_PREC) {
data[pos] = (short) 0x8001;
} else {
int f = Float.floatToIntBits(flt);
if (f == 0x7fc00000)
throw new UnsupportedOperationException(
"NaN to half conversion not supported!");
data[pos] = (short) (((f >> 16) & 0x8000)
| ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00)
| ((f >> 13) & 0x03ff));
}
}
} }

View File

@@ -14,7 +14,6 @@
*/ */
package org.mapsforge.core; package org.mapsforge.core;
/** /**
* A tile represents a rectangular part of the world map. All tiles can be identified by their X and Y number together * A tile represents a rectangular part of the world map. All tiles can be identified by their X and Y number together
* with their zoom level. The actual area that a tile covers on a map depends on the underlying map projection. * with their zoom level. The actual area that a tile covers on a map depends on the underlying map projection.
@@ -33,7 +32,8 @@ public class Tile {
/** /**
* Size of a single uncompressed map tile bitmap in bytes. * Size of a single uncompressed map tile bitmap in bytes.
*/ */
public static final int TILE_SIZE_IN_BYTES = TILE_SIZE * TILE_SIZE * TILE_BYTES_PER_PIXEL; public static final int TILE_SIZE_IN_BYTES = TILE_SIZE * TILE_SIZE
* TILE_BYTES_PER_PIXEL;
/** /**
* The X number of this tile. * The X number of this tile.

View File

@@ -254,11 +254,14 @@ public class MapDatabase implements IMapDatabase {
try { try {
prepareExecution(); prepareExecution();
QueryParameters queryParameters = new QueryParameters(); QueryParameters queryParameters = new QueryParameters();
queryParameters.queryZoomLevel = mMapFileHeader.getQueryZoomLevel(tile.zoomLevel); queryParameters.queryZoomLevel = mMapFileHeader
.getQueryZoomLevel(tile.zoomLevel);
// get and check the sub-file for the query zoom level // get and check the sub-file for the query zoom level
SubFileParameter subFileParameter = mMapFileHeader.getSubFileParameter(queryParameters.queryZoomLevel); SubFileParameter subFileParameter = mMapFileHeader
.getSubFileParameter(queryParameters.queryZoomLevel);
if (subFileParameter == null) { if (subFileParameter == null) {
LOG.warning("no sub-file for zoom level: " + queryParameters.queryZoomLevel); LOG.warning("no sub-file for zoom level: "
+ queryParameters.queryZoomLevel);
return; return;
} }
@@ -320,7 +323,8 @@ public class MapDatabase implements IMapDatabase {
mReadBuffer = new ReadBuffer(mInputFile); mReadBuffer = new ReadBuffer(mInputFile);
mMapFileHeader = new MapFileHeader(); mMapFileHeader = new MapFileHeader();
FileOpenResult fileOpenResult = mMapFileHeader.readHeader(mReadBuffer, mFileSize); FileOpenResult fileOpenResult = mMapFileHeader.readHeader(mReadBuffer,
mFileSize);
if (!fileOpenResult.isSuccess()) { if (!fileOpenResult.isSuccess()) {
closeFile(); closeFile();
return fileOpenResult; return fileOpenResult;
@@ -361,7 +365,8 @@ public class MapDatabase implements IMapDatabase {
* @param mapDatabaseCallback * @param mapDatabaseCallback
* the callback which handles the extracted map elements. * the callback which handles the extracted map elements.
*/ */
private void processBlock(QueryParameters queryParameters, SubFileParameter subFileParameter, private void processBlock(QueryParameters queryParameters,
SubFileParameter subFileParameter,
IMapDatabaseCallback mapDatabaseCallback) { IMapDatabaseCallback mapDatabaseCallback) {
if (!processBlockSignature()) { if (!processBlockSignature()) {
return; return;
@@ -416,7 +421,8 @@ public class MapDatabase implements IMapDatabase {
} }
private void processBlocks(IMapDatabaseCallback mapDatabaseCallback, QueryParameters queryParameters, private void processBlocks(IMapDatabaseCallback mapDatabaseCallback,
QueryParameters queryParameters,
SubFileParameter subFileParameter) throws IOException { SubFileParameter subFileParameter) throws IOException {
boolean queryIsWater = true; boolean queryIsWater = true;
// boolean queryReadWaterInfo = false; // boolean queryReadWaterInfo = false;
@@ -429,7 +435,8 @@ public class MapDatabase implements IMapDatabase {
long blockNumber = row * subFileParameter.blocksWidth + column; long blockNumber = row * subFileParameter.blocksWidth + column;
// get the current index entry // get the current index entry
long currentBlockIndexEntry = mDatabaseIndexCache.getIndexEntry(subFileParameter, blockNumber); long currentBlockIndexEntry = mDatabaseIndexCache.getIndexEntry(
subFileParameter, blockNumber);
// check if the current query would still return a water tile // check if the current query would still return a water tile
if (queryIsWater) { if (queryIsWater) {
@@ -440,7 +447,8 @@ public class MapDatabase implements IMapDatabase {
// get and check the current block pointer // get and check the current block pointer
long currentBlockPointer = currentBlockIndexEntry & BITMASK_INDEX_OFFSET; long currentBlockPointer = currentBlockIndexEntry & BITMASK_INDEX_OFFSET;
if (currentBlockPointer < 1 || currentBlockPointer > subFileParameter.subFileSize) { if (currentBlockPointer < 1
|| currentBlockPointer > subFileParameter.subFileSize) {
LOG.warning("invalid current block pointer: " + currentBlockPointer); LOG.warning("invalid current block pointer: " + currentBlockPointer);
LOG.warning("subFileSize: " + subFileParameter.subFileSize); LOG.warning("subFileSize: " + subFileParameter.subFileSize);
return; return;
@@ -453,9 +461,11 @@ public class MapDatabase implements IMapDatabase {
nextBlockPointer = subFileParameter.subFileSize; nextBlockPointer = subFileParameter.subFileSize;
} else { } else {
// get and check the next block pointer // get and check the next block pointer
nextBlockPointer = mDatabaseIndexCache.getIndexEntry(subFileParameter, blockNumber + 1) nextBlockPointer = mDatabaseIndexCache.getIndexEntry(
subFileParameter, blockNumber + 1)
& BITMASK_INDEX_OFFSET; & BITMASK_INDEX_OFFSET;
if (nextBlockPointer < 1 || nextBlockPointer > subFileParameter.subFileSize) { if (nextBlockPointer < 1
|| nextBlockPointer > subFileParameter.subFileSize) {
LOG.warning("invalid next block pointer: " + nextBlockPointer); LOG.warning("invalid next block pointer: " + nextBlockPointer);
LOG.warning("sub-file size: " + subFileParameter.subFileSize); LOG.warning("sub-file size: " + subFileParameter.subFileSize);
return; return;
@@ -465,7 +475,8 @@ public class MapDatabase implements IMapDatabase {
// calculate the size of the current block // calculate the size of the current block
int currentBlockSize = (int) (nextBlockPointer - currentBlockPointer); int currentBlockSize = (int) (nextBlockPointer - currentBlockPointer);
if (currentBlockSize < 0) { if (currentBlockSize < 0) {
LOG.warning("current block size must not be negative: " + currentBlockSize); LOG.warning("current block size must not be negative: "
+ currentBlockSize);
return; return;
} else if (currentBlockSize == 0) { } else if (currentBlockSize == 0) {
// the current block is empty, continue with the next block // the current block is empty, continue with the next block
@@ -475,7 +486,8 @@ public class MapDatabase implements IMapDatabase {
LOG.warning("current block size too large: " + currentBlockSize); LOG.warning("current block size too large: " + currentBlockSize);
continue; continue;
} else if (currentBlockPointer + currentBlockSize > mFileSize) { } else if (currentBlockPointer + currentBlockSize > mFileSize) {
LOG.warning("current block largher than file size: " + currentBlockSize); LOG.warning("current block largher than file size: "
+ currentBlockSize);
return; return;
} }
@@ -490,10 +502,12 @@ public class MapDatabase implements IMapDatabase {
} }
// calculate the top-left coordinates of the underlying tile // calculate the top-left coordinates of the underlying tile
double tileLatitudeDeg = MercatorProjection.tileYToLatitude(subFileParameter.boundaryTileTop + row, double tileLatitudeDeg = MercatorProjection.tileYToLatitude(
subFileParameter.boundaryTileTop + row,
subFileParameter.baseZoomLevel); subFileParameter.baseZoomLevel);
double tileLongitudeDeg = MercatorProjection.tileXToLongitude(subFileParameter.boundaryTileLeft double tileLongitudeDeg = MercatorProjection.tileXToLongitude(
+ column, subFileParameter.baseZoomLevel); subFileParameter.boundaryTileLeft
+ column, subFileParameter.baseZoomLevel);
mTileLatitude = (int) (tileLatitudeDeg * 1000000); mTileLatitude = (int) (tileLatitudeDeg * 1000000);
mTileLongitude = (int) (tileLongitudeDeg * 1000000); mTileLongitude = (int) (tileLongitudeDeg * 1000000);
@@ -544,7 +558,6 @@ public class MapDatabase implements IMapDatabase {
* @return true if the POIs could be processed successfully, false otherwise. * @return true if the POIs could be processed successfully, false otherwise.
*/ */
private boolean processPOIs(IMapDatabaseCallback mapDatabaseCallback, int numberOfPois) { private boolean processPOIs(IMapDatabaseCallback mapDatabaseCallback, int numberOfPois) {
// List<Tag> tags = new ArrayList<Tag>();
Tag[] poiTags = mMapFileHeader.getMapFileInfo().poiTags; Tag[] poiTags = mMapFileHeader.getMapFileInfo().poiTags;
Tag[] tags = null; Tag[] tags = null;
@@ -586,22 +599,19 @@ public class MapDatabase implements IMapDatabase {
byte featureByte = mReadBuffer.readByte(); byte featureByte = mReadBuffer.readByte();
// bit 1-3 enable optional features // bit 1-3 enable optional features
boolean featureName = (featureByte & POI_FEATURE_NAME) != 0;
boolean featureHouseNumber = (featureByte & POI_FEATURE_HOUSE_NUMBER) != 0;
boolean featureElevation = (featureByte & POI_FEATURE_ELEVATION) != 0;
// check if the POI has a name // check if the POI has a name
if (featureName) { if ((featureByte & POI_FEATURE_NAME) != 0) {
mReadBuffer.getPositionAndSkip(); mReadBuffer.getPositionAndSkip();
} }
// check if the POI has a house number // check if the POI has a house number
if (featureHouseNumber) { if ((featureByte & POI_FEATURE_HOUSE_NUMBER) != 0) {
mReadBuffer.getPositionAndSkip(); mReadBuffer.getPositionAndSkip();
} }
// check if the POI has an elevation // check if the POI has an elevation
if (featureElevation) { if ((featureByte & POI_FEATURE_ELEVATION) != 0) {
mReadBuffer.readSignedInt(); mReadBuffer.readSignedInt();
// mReadBuffer.getPositionAndSkip();// tags.add(new Tag(Tag.TAG_KEY_ELE, // mReadBuffer.getPositionAndSkip();// tags.add(new Tag(Tag.TAG_KEY_ELE,
// Integer.toString(mReadBuffer.readSignedInt()))); // Integer.toString(mReadBuffer.readSignedInt())));
@@ -686,7 +696,8 @@ public class MapDatabase implements IMapDatabase {
dLon = nLon - wayNodeLongitude; dLon = nLon - wayNodeLongitude;
wayNodeLongitude = nLon; wayNodeLongitude = nLon;
if (dLon > minLon || dLon < -minLon || dLat > minLat || dLat < -minLat || (pos == length - 2)) { if (dLon > minLon || dLon < -minLon || dLat > minLat || dLat < -minLat
|| (pos == length - 2)) {
outBuffer[floatPos++] = nLon; outBuffer[floatPos++] = nLon;
outBuffer[floatPos++] = nLat; outBuffer[floatPos++] = nLat;
cnt += 2; cnt += 2;
@@ -727,7 +738,8 @@ public class MapDatabase implements IMapDatabase {
dLon = nLon - wayNodeLongitude; dLon = nLon - wayNodeLongitude;
wayNodeLongitude = nLon; wayNodeLongitude = nLon;
if (dLon > minLon || dLon < -minLon || dLat > minLat || dLat < -minLat || (pos == length - 2)) { if (dLon > minLon || dLon < -minLon || dLat > minLat || dLat < -minLat
|| (pos == length - 2)) {
outBuffer[floatPos++] = nLon; outBuffer[floatPos++] = nLon;
outBuffer[floatPos++] = nLat; outBuffer[floatPos++] = nLat;
cnt += 2; cnt += 2;
@@ -760,7 +772,8 @@ public class MapDatabase implements IMapDatabase {
* how many ways should be processed. * how many ways should be processed.
* @return true if the ways could be processed successfully, false otherwise. * @return true if the ways could be processed successfully, false otherwise.
*/ */
private boolean processWays(QueryParameters queryParameters, IMapDatabaseCallback mapDatabaseCallback, private boolean processWays(QueryParameters queryParameters,
IMapDatabaseCallback mapDatabaseCallback,
int numberOfWays) { int numberOfWays) {
Tag[] tags = null; Tag[] tags = null;
@@ -787,7 +800,8 @@ public class MapDatabase implements IMapDatabase {
} }
if (queryParameters.useTileBitmask) { if (queryParameters.useTileBitmask) {
elementCounter = mReadBuffer.skipWays(queryParameters.queryTileBitmask, elementCounter); elementCounter = mReadBuffer.skipWays(queryParameters.queryTileBitmask,
elementCounter);
if (elementCounter == 0) if (elementCounter == 0)
return true; return true;
@@ -890,7 +904,8 @@ public class MapDatabase implements IMapDatabase {
return false; return false;
// wayDataContainer.textPos = textPos; // wayDataContainer.textPos = textPos;
mapDatabaseCallback.renderWay(layer, tags, mWayNodes, wayLengths, changed); mapDatabaseCallback
.renderWay(layer, tags, mWayNodes, wayLengths, changed);
} }
} }
@@ -929,14 +944,18 @@ public class MapDatabase implements IMapDatabase {
cumulatedNumberOfPois += mReadBuffer.readUnsignedInt(); cumulatedNumberOfPois += mReadBuffer.readUnsignedInt();
cumulatedNumberOfWays += mReadBuffer.readUnsignedInt(); cumulatedNumberOfWays += mReadBuffer.readUnsignedInt();
if (cumulatedNumberOfPois < 0 || cumulatedNumberOfPois > MAXIMUM_ZOOM_TABLE_OBJECTS) { if (cumulatedNumberOfPois < 0
LOG.warning("invalid cumulated number of POIs in row " + row + ' ' + cumulatedNumberOfPois); || cumulatedNumberOfPois > MAXIMUM_ZOOM_TABLE_OBJECTS) {
LOG.warning("invalid cumulated number of POIs in row " + row + ' '
+ cumulatedNumberOfPois);
if (mDebugFile) { if (mDebugFile) {
LOG.warning(DEBUG_SIGNATURE_BLOCK + mSignatureBlock); LOG.warning(DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
} }
return null; return null;
} else if (cumulatedNumberOfWays < 0 || cumulatedNumberOfWays > MAXIMUM_ZOOM_TABLE_OBJECTS) { } else if (cumulatedNumberOfWays < 0
LOG.warning("invalid cumulated number of ways in row " + row + ' ' + cumulatedNumberOfWays); || cumulatedNumberOfWays > MAXIMUM_ZOOM_TABLE_OBJECTS) {
LOG.warning("invalid cumulated number of ways in row " + row + ' '
+ cumulatedNumberOfWays);
if (mMapFileHeader.getMapFileInfo().debugFile) { if (mMapFileHeader.getMapFileInfo().debugFile) {
LOG.warning(DEBUG_SIGNATURE_BLOCK + mSignatureBlock); LOG.warning(DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
} }