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);
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);
setWillNotCacheDrawing(true);
@@ -138,7 +139,8 @@ public class MapView extends GLSurfaceView {
mMapController = new MapController(this);
// mMapDatabase = MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.POSTGIS_READER);
mMapDatabase = MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.MAP_READER);
mMapDatabase = MapDatabaseFactory
.createMapDatabase(MapDatabaseInternal.MAP_READER);
mMapViewPosition = new MapViewPosition(this);
mMapScaleBar = new MapScaleBar(this);
@@ -327,7 +329,8 @@ public class MapView extends GLSurfaceView {
* the new center point of the map.
*/
public void setCenter(GeoPoint geoPoint) {
MapPosition mapPosition = new MapPosition(geoPoint, mMapViewPosition.getZoomLevel(), 1);
MapPosition mapPosition = new MapPosition(geoPoint,
mMapViewPosition.getZoomLevel(), 1);
setCenterAndZoom(mapPosition);
}
@@ -566,16 +569,22 @@ public class MapView extends GLSurfaceView {
protected final void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// find out how big the zoom controls should be
mMapZoomControls.measure(
MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.AT_MOST));
MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
MeasureSpec.AT_MOST));
// make sure that MapView is big enough to display the zoom controls
setMeasuredDimension(Math.max(MeasureSpec.getSize(widthMeasureSpec), mMapZoomControls.getMeasuredWidth()),
Math.max(MeasureSpec.getSize(heightMeasureSpec), mMapZoomControls.getMeasuredHeight()));
setMeasuredDimension(
Math.max(MeasureSpec.getSize(widthMeasureSpec),
mMapZoomControls.getMeasuredWidth()),
Math.max(MeasureSpec.getSize(heightMeasureSpec),
mMapZoomControls.getMeasuredHeight()));
}
@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.awaitPausing();
super.onSizeChanged(width, height, oldWidth, oldHeight);
@@ -605,7 +614,8 @@ public class MapView extends GLSurfaceView {
* @return the maximum possible zoom level.
*/
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()) {
return false;
} else if (!mMapGenerator.requiresInternetConnection()
&& (!mMapDatabase.hasOpenFile() || !mMapDatabase.getMapFileInfo().boundingBox.contains(getMapPosition()
.getMapCenter()))) {
&& (!mMapDatabase.hasOpenFile() || !mMapDatabase.getMapFileInfo().boundingBox
.contains(getMapPosition()
.getMapCenter()))) {
return false;
}
@@ -624,7 +635,8 @@ public class MapView extends GLSurfaceView {
}
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,74 +15,79 @@
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)
class PoolItem {
final float[] vertices;
// final byte[] vertices;
int used;
PoolItem() {
vertices = new float[SIZE];
// vertices = new byte[SIZE];
used = 0;
}
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_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;
for (int j = 0; j < item.used; j++) {
float flt = item.vertices[j];
int f = intArray[j];
if (flt == 0f) {
data[out++] = b0x00;
data[out++] = b0x00;
} else if (flt == -0f) {
data[out++] = b0x00;
data[out++] = b0x80;
if (f == 0x0000000) {
// == 0
data[out++] = (short) 0x0000;
} else if (f == 0x80000000) {
// == -0
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) {
if (flt == Float.POSITIVE_INFINITY) {
data[out++] = b0x00;
data[out++] = b0x7c;
data[out++] = (short) 0x7c00;
} else {
data[out++] = b0xff;
data[out++] = b0x7b;
data[out++] = (short) 0x7bff;
}
} else if (flt < -FLOAT_HALF_MAX) {
if (flt == Float.NEGATIVE_INFINITY) {
data[out++] = b0x00;
data[out++] = b0xfc;
data[out++] = (short) 0xfc00;
} else {
data[out++] = b0xff;
data[out++] = b0xfb;
data[out++] = (short) 0xfbff;
}
} else if (flt > 0f && flt < FLOAT_HALF_PREC) {
data[out++] = b0x01;
data[out++] = b0x00;
data[out++] = (short) 0x0001;
} else if (flt < 0f && flt > -FLOAT_HALF_PREC) {
data[out++] = b0x01;
data[out++] = b0x80;
data[out++] = (short) 0x8001;
} else {
int f = Float.floatToIntBits(flt);
// maybe just ignore and set 0? -- we'll see. when this happens
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++] = (byte) (((f >> 24) & 0x80) | ((((f & 0x7f800000) - 0x38000000) >> 21) & 0x7c) | ((f >> 21) & 0x03));
data[out++] = (short) (((f >> 16) & 0x8000)
| ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00)
| ((f >> 13) & 0x03ff));
}
}
}

View File

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

View File

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

View File

@@ -1,8 +1,7 @@
package org.mapsforge.android.utils;
/**
* Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved. FastMath.java
* Copyright (c) 2009-2010 jMonkeyEngine All rights reserved. FastMath.java
*/
public class FastMath {
@@ -58,7 +57,8 @@ public class FastMath {
int f = Float.floatToIntBits(flt);
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)
| ((((f & 0x7f800000) - 0x38000000) >> 21) & 0x7c)
@@ -67,4 +67,50 @@ public class FastMath {
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));
}
}
}