- pack line texture coordinates in least significant bits of extrusion vector

- saving 4 bytes per vertex :)
- use premultiplied alpha,fixing issues on HTC and no reason no to use premul
- fix issue on HTC desire, went out-of-memory when setting buffer data to zero ?!
  - delete buffer and rereate instead
- use 565 color config for devices that prefer it (HTC...)
This commit is contained in:
Hannes Janetzek 2012-09-06 01:06:35 +02:00
parent 7f469a6316
commit 7c95930ba3
12 changed files with 265 additions and 604 deletions

View File

@ -78,6 +78,8 @@ public class MapView extends GLSurfaceView {
private static final float DEFAULT_TEXT_SCALE = 1;
private static final Byte DEFAULT_START_ZOOM_LEVEL = Byte.valueOf((byte) 16);
public final static boolean debugFrameTime = false;
private final MapController mMapController;
private final MapViewPosition mMapViewPosition;
@ -186,6 +188,7 @@ public class MapView extends GLSurfaceView {
setEGLConfigChooser(new GlConfigChooser());
setEGLContextClientVersion(2);
// setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
setRenderer(mMapRenderer);
@ -193,8 +196,6 @@ public class MapView extends GLSurfaceView {
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
public final static boolean debugFrameTime = false;
private void initMapStartPosition() {
GeoPoint startPoint = getStartPoint();
if (startPoint != null) {

View File

@ -22,10 +22,16 @@ import android.util.FloatMath;
class LineLayer {
private static final float S = MapRenderer.COORD_MULTIPLIER;
private static final float S1000 = 1000;
private static final float COORD_SCALE = MapRenderer.COORD_MULTIPLIER;
// scale factor mapping direction vector to short values
private static final float DIR_SCALE = 2048;
// mask for packing last two bits of direction vector with texture coordinates
private static final int DIR_MASK = 0xFFFFFFFC;
// next layer
LineLayer next;
// lines referenced by this outline layer
LineLayer outlines;
Line line;
@ -58,12 +64,12 @@ class LineLayer {
}
/*
* line extrusion is based on code from GLMap (https://github.com/olofsj/GLMap/) by olofsj -- need some way to know
* how the road connects to set the ending angles
* line extrusion is based on code from GLMap (https://github.com/olofsj/GLMap/) by olofsj
*/
void addLine(float[] points, int pos, int length) {
float x, y, nextX, nextY, prevX, prevY, ux, uy, vx, vy, wx, wy;
float a;
float x, y, nextX, nextY, prevX, prevY;
float a, ux, uy, vx, vy, wx, wy;
int ipos = pos;
boolean rounded = false;
boolean squared = false;
@ -94,7 +100,8 @@ class LineLayer {
ux = -vy;
uy = vx;
int tsize = Tile.TILE_SIZE;
int tmax = Tile.TILE_SIZE + 10;
int tmin = -10;
if (pool == null) {
pool = curItem = ShortPool.get();
@ -112,27 +119,25 @@ class LineLayer {
v = si.vertices;
}
boolean outside = (x <= 0 || x >= tsize || y <= 0 || y >= tsize)
&& (x - vx <= 0 || x - vx >= tsize || y - vy <= 0 || y - vy >= tsize);
short ox, oy, dx, dy;
int ddx, ddy;
ox = (short) (x * S);
oy = (short) (y * S);
ox = (short) (x * COORD_SCALE);
oy = (short) (y * COORD_SCALE);
boolean outside = (x < tmin || x > tmax || y < tmin || y > tmax);
if (rounded && !outside) {
// add first vertex twice
ddx = (int) ((ux - vx) * DIR_SCALE);
ddy = (int) ((uy - vy) * DIR_SCALE);
dx = (short) (0 | ddx & DIR_MASK);
dy = (short) (2 | ddy & DIR_MASK);
// For rounded line edges
dx = (short) ((ux - vx) * S1000);
dy = (short) ((uy - vy) * S1000);
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = -1;
v[opos + 5] = 1;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -142,13 +147,10 @@ class LineLayer {
v = si.vertices;
}
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = -1;
v[opos + 5] = 1;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -158,16 +160,13 @@ class LineLayer {
v = si.vertices;
}
dx = (short) (-(ux + vx) * S1000);
dy = (short) (-(uy + vy) * S1000);
ddx = (int) (-(ux + vx) * DIR_SCALE);
ddy = (int) (-(uy + vy) * DIR_SCALE);
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = 1;
v[opos + 5] = 1;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = (short) (2 | ddx & DIR_MASK);
v[opos++] = (short) (2 | ddy & DIR_MASK);
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -178,16 +177,13 @@ class LineLayer {
}
// Start of line
dx = (short) (ux * S1000);
dy = (short) (uy * S1000);
ddx = (int) (ux * DIR_SCALE);
ddy = (int) (uy * DIR_SCALE);
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = -1;
v[opos + 5] = 0;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = (short) (0 | ddx & DIR_MASK);
v[opos++] = (short) (1 | ddy & DIR_MASK);
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -197,13 +193,10 @@ class LineLayer {
v = si.vertices;
}
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = (short) (-dx);
v[opos + 3] = (short) (-dy);
v[opos + 4] = 1;
v[opos + 5] = 0;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = (short) (2 | -ddx & DIR_MASK);
v[opos++] = (short) (1 | -ddy & DIR_MASK);
} else {
// outside means line is probably clipped
@ -221,16 +214,16 @@ class LineLayer {
if (rounded)
verticesCnt -= 2;
dx = (short) ((ux - vx) * S1000);
dy = (short) ((uy - vy) * S1000);
// add first vertex twice
ddx = (int) ((ux - vx) * DIR_SCALE);
ddy = (int) ((uy - vy) * DIR_SCALE);
dx = (short) (0 | ddx & DIR_MASK);
dy = (short) (1 | ddy & DIR_MASK);
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = -1;
v[opos + 5] = 0;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -240,13 +233,10 @@ class LineLayer {
v = si.vertices;
}
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = -1;
v[opos + 5] = 0;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -256,16 +246,14 @@ class LineLayer {
v = si.vertices;
}
dx = (short) (-(ux + vx) * S1000);
dy = (short) (-(uy + vy) * S1000);
ddx = (int) (-(ux + vx) * DIR_SCALE);
ddy = (int) (-(uy + vy) * DIR_SCALE);
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = (short) (2 | ddx & DIR_MASK);
v[opos++] = (short) (1 | ddy & DIR_MASK);
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = 1;
v[opos + 5] = 0;
opos += 6;
}
prevX = x;
@ -298,14 +286,16 @@ class LineLayer {
a = -wy * ux + wx * uy;
// boolean split = false;
if (a < 0.1f && a > -0.1f) {
// Almost straight or miter goes to infinity, use normal vector
if (a < 0.01f && a > -0.01f) {
// Almost straight
ux = -wy;
uy = wx;
} else {
ux = (ux / a);
uy = (uy / a);
// hack to avoid miter going to infinity
// note to myself: find my mathbook and do this properly!
if (ux > 2.0f || ux < -2.0f || uy > 2.0f || uy < -2.0f) {
ux = -wy;
uy = wx;
@ -320,19 +310,16 @@ class LineLayer {
v = si.vertices;
}
ox = (short) (x * S);
oy = (short) (y * S);
ox = (short) (x * COORD_SCALE);
oy = (short) (y * COORD_SCALE);
dx = (short) (ux * S1000);
dy = (short) (uy * S1000);
ddx = (int) (ux * DIR_SCALE);
ddy = (int) (uy * DIR_SCALE);
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = -1;
v[opos + 5] = 0;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = (short) (0 | ddx & DIR_MASK);
v[opos++] = (short) (1 | ddy & DIR_MASK);
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -342,13 +329,10 @@ class LineLayer {
v = si.vertices;
}
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = (short) -dx;
v[opos + 3] = (short) -dy;
v[opos + 4] = 1;
v[opos + 5] = 0;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = (short) (2 | -ddx & DIR_MASK);
v[opos++] = (short) (1 | -ddy & DIR_MASK);
prevX = x;
prevY = y;
@ -367,8 +351,7 @@ class LineLayer {
ux = vy;
uy = -vx;
outside = (x <= 0 || x >= tsize || y <= 0 || y >= tsize)
&& (x - vx <= 0 || x - vx >= tsize || y - vy <= 0 || y - vy >= tsize);
outside = (x < tmin || x > tmax || y < tmin || y > tmax);
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -378,21 +361,17 @@ class LineLayer {
v = si.vertices;
}
ox = (short) (x * S);
oy = (short) (y * S);
ox = (short) (x * COORD_SCALE);
oy = (short) (y * COORD_SCALE);
if (rounded && !outside) {
ddx = (int) (ux * DIR_SCALE);
ddy = (int) (uy * DIR_SCALE);
dx = (short) (ux * S1000);
dy = (short) (uy * S1000);
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = -1;
v[opos + 5] = 0;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = (short) (0 | ddx & DIR_MASK);
v[opos++] = (short) (1 | ddy & DIR_MASK);
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -402,13 +381,10 @@ class LineLayer {
v = si.vertices;
}
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = (short) -dx;
v[opos + 3] = (short) -dy;
v[opos + 4] = 1;
v[opos + 5] = 0;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = (short) (2 | -ddx & DIR_MASK);
v[opos++] = (short) (1 | -ddy & DIR_MASK);
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -419,16 +395,15 @@ class LineLayer {
}
// For rounded line edges
dx = (short) ((ux - vx) * S1000);
dy = (short) ((uy - vy) * S1000);
ddx = (int) ((ux - vx) * DIR_SCALE);
ddy = (int) ((uy - vy) * DIR_SCALE);
dx = (short) (0 | ddx & DIR_MASK);
dy = (short) (0 | ddy & DIR_MASK);
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = -1;
v[opos + 5] = -1;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -438,16 +413,16 @@ class LineLayer {
v = si.vertices;
}
dx = (short) (-(ux + vx) * S1000);
dy = (short) (-(uy + vy) * S1000);
// add last vertex twice
ddx = (int) (-(ux + vx) * DIR_SCALE);
ddy = (int) (-(uy + vy) * DIR_SCALE);
dx = (short) (2 | ddx & DIR_MASK);
dy = (short) (0 | ddy & DIR_MASK);
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = 1;
v[opos + 5] = -1;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -457,13 +432,10 @@ class LineLayer {
v = si.vertices;
}
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = 1;
v[opos + 5] = -1;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = dx;
v[opos++] = dy;
} else {
if (squared) {
@ -477,16 +449,13 @@ class LineLayer {
if (rounded)
verticesCnt -= 2;
dx = (short) ((ux - vx) * S1000);
dy = (short) ((uy - vy) * S1000);
ddx = (int) ((ux - vx) * DIR_SCALE);
ddy = (int) ((uy - vy) * DIR_SCALE);
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = -1;
v[opos + 5] = 0;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = (short) (0 | ddx & DIR_MASK);
v[opos++] = (short) (1 | ddy & DIR_MASK);
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -496,16 +465,16 @@ class LineLayer {
v = si.vertices;
}
dx = (short) (-(ux + vx) * S1000);
dy = (short) (-(uy + vy) * S1000);
// add last vertex twice
ddx = (int) (-(ux + vx) * DIR_SCALE);
ddy = (int) (-(uy + vy) * DIR_SCALE);
dx = (short) (2 | ddx & DIR_MASK);
dy = (short) (1 | ddy & DIR_MASK);
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = 1;
v[opos + 5] = 0;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si.used = ShortItem.SIZE;
@ -515,13 +484,10 @@ class LineLayer {
v = si.vertices;
}
v[opos + 0] = ox;
v[opos + 1] = oy;
v[opos + 2] = dx;
v[opos + 3] = dy;
v[opos + 4] = 1;
v[opos + 5] = 0;
opos += 6;
v[opos++] = ox;
v[opos++] = oy;
v[opos++] = dx;
v[opos++] = dy;
}
si.used = opos;

View File

@ -35,10 +35,10 @@ import android.opengl.GLES20;
import android.util.FloatMath;
class LineLayers {
private static int NUM_VERTEX_SHORTS = 6;
private static int NUM_VERTEX_SHORTS = 4;
private static final int LINE_VERTICES_DATA_POS_OFFSET = 0;
private static final int LINE_VERTICES_DATA_TEX_OFFSET = 8;
private static final int LINE_VERTICES_DATA_TEX_OFFSET = 4;
// shader handles
private static int lineProgram;
@ -82,11 +82,11 @@ class LineLayers {
glEnableVertexAttribArray(hLineVertexPosition);
glEnableVertexAttribArray(hLineTexturePosition);
glVertexAttribPointer(hLineVertexPosition, 4, GLES20.GL_SHORT,
false, 12, tile.lineOffset + LINE_VERTICES_DATA_POS_OFFSET);
glVertexAttribPointer(hLineVertexPosition, 2, GLES20.GL_SHORT,
false, 8, tile.lineOffset + LINE_VERTICES_DATA_POS_OFFSET);
glVertexAttribPointer(hLineTexturePosition, 2, GLES20.GL_SHORT,
false, 12, tile.lineOffset + LINE_VERTICES_DATA_TEX_OFFSET);
false, 8, tile.lineOffset + LINE_VERTICES_DATA_TEX_OFFSET);
glUniformMatrix4fv(hLineMatrix, 1, false, matrix, 0);
@ -115,7 +115,10 @@ class LineLayers {
if (alpha > 1.0f)
alpha = 1.0f;
glUniform4f(hLineColor,
line.color[0], line.color[1], line.color[2], alpha);
line.color[0] * alpha,
line.color[1] * alpha,
line.color[2] * alpha,
alpha);
} else {
glUniform4fv(hLineColor, 1, line.color, 0);
}

View File

@ -16,11 +16,9 @@ package org.mapsforge.android.glrenderer;
import static android.opengl.GLES20.GL_ARRAY_BUFFER;
import static android.opengl.GLES20.GL_BLEND;
import static android.opengl.GLES20.GL_DITHER;
import static android.opengl.GLES20.GL_DYNAMIC_DRAW;
import static android.opengl.GLES20.GL_ONE_MINUS_SRC_ALPHA;
import static android.opengl.GLES20.GL_SCISSOR_TEST;
import static android.opengl.GLES20.GL_SRC_ALPHA;
import static android.opengl.GLES20.GL_STENCIL_BUFFER_BIT;
import static android.opengl.GLES20.glBindBuffer;
import static android.opengl.GLES20.glBlendFunc;
@ -30,7 +28,6 @@ import static android.opengl.GLES20.glClearColor;
import static android.opengl.GLES20.glClearStencil;
import static android.opengl.GLES20.glDisable;
import static android.opengl.GLES20.glEnable;
import static android.opengl.GLES20.glFinish;
import static android.opengl.GLES20.glGenBuffers;
import static android.opengl.GLES20.glScissor;
import static android.opengl.GLES20.glViewport;
@ -68,7 +65,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
private static final int MAX_TILES_IN_QUEUE = 40;
private static final int CACHE_TILES_MAX = 250;
private static final int LIMIT_BUFFERS = 16 * MB;
private static final int LIMIT_BUFFERS = 12 * MB;
private static int CACHE_TILES = CACHE_TILES_MAX;
@ -109,7 +106,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
private static float[] mMVPMatrix = new float[16];
// private static float[] mRotateMatrix = new float[16];
private static float[] mProjMatrix = new float[16];
// private static float[] mProjMatrix = new float[16];
// newTiles is set in updateVisibleList and swapped
// with curTiles on main thread. curTiles is swapped
@ -600,6 +597,12 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
return true;
}
// depthRange: -1 to 1, bits: 2^24 => 2/2^24 one step
// maybe one could avoid clearing the depth buffer for a few
// iterations when modifying glDepthRange before clipper
// gl_less test so that it does not fail
// private static final float depthStep = 0.00000011920928955078125f;
private static void setMatrix(GLMapTile tile, float div, int offset) {
float x, y, scale;
@ -609,7 +612,8 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
mMVPMatrix[12] = x * scale * mAspect;
mMVPMatrix[13] = -(y + Tile.TILE_SIZE) * scale;
mMVPMatrix[14] = offset * 0.01f;
// increase the 'distance' with each tile drawn.
mMVPMatrix[14] = -1 + offset * 0.01f; // depthStep; // 0.01f;
mMVPMatrix[0] = scale * mAspect / COORD_MULTIPLIER;
mMVPMatrix[5] = scale / COORD_MULTIPLIER;
@ -763,6 +767,9 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
if (mBufferMemoryUsage > LIMIT_BUFFERS) {
Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / MB + "MB");
glBindBuffer(GL_ARRAY_BUFFER, 0);
int buf[] = new int[1];
synchronized (mVBOs) {
for (VertexBufferObject vbo : mVBOs) {
@ -770,8 +777,19 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
continue;
mBufferMemoryUsage -= vbo.size;
glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
glBufferData(GL_ARRAY_BUFFER, 0, null, GL_DYNAMIC_DRAW);
GlUtils.checkGlError("before");
// this should free allocated memory but it does not. at least on HTC.
// glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
// glBufferData(GL_ARRAY_BUFFER, 0, null, GLES20.GL_STATIC_DRAW);
// recreate vbo
buf[0] = vbo.id;
GLES20.glDeleteBuffers(1, buf, 0);
GLES20.glGenBuffers(1, buf, 0);
vbo.id = buf[0];
GlUtils.checkGlError("after");
vbo.size = 0;
}
}
@ -801,7 +819,14 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
}
GLES20.glDepthMask(true);
glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Note: i have the impression it is faster to also clear the
// stencil buffer even when not needed. probaly otherwise it
// is masked out from the depth buffer as they share the same
// memory region afaik
glClear(GLES20.GL_COLOR_BUFFER_BIT
| GLES20.GL_DEPTH_BUFFER_BIT
| GLES20.GL_STENCIL_BUFFER_BIT);
if (mInitial)
return;
@ -862,7 +887,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
if (updateTextures > 0)
TextRenderer.compileTextures();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
// glEnable(GLES20.GL_POLYGON_OFFSET_FILL);
@ -883,17 +907,15 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
// glDisable(GLES20.GL_POLYGON_OFFSET_FILL);
glDisable(GLES20.GL_DEPTH_TEST);
//
mDrawCount = 0;
glEnable(GL_BLEND);
glBlendFunc(GLES20.GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
int z = mDrawPosition.zoomLevel;
float s = mDrawPosition.scale;
int zoomLevelDiff = Math
.max(z - MapGenerator.STROKE_MAX_ZOOM_LEVEL, 0);
int zoomLevelDiff = Math.max(z - MapGenerator.STROKE_MAX_ZOOM_LEVEL, 0);
float scale = (float) Math.pow(1.4, zoomLevelDiff);
if (scale < 1)
scale = 1;
@ -913,7 +935,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
TextRenderer.endDraw();
if (MapView.debugFrameTime) {
glFinish();
GLES20.glFinish();
Log.d(TAG, "draw took " + (SystemClock.uptimeMillis() - start));
}
@ -921,19 +943,20 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
}
private static void drawTile(GLMapTile tile, float div) {
// draw parents only once
if (tile.lastDraw == mRedrawCnt)
return;
tile.lastDraw = mRedrawCnt;
int z = mDrawPosition.zoomLevel;
float s = mDrawPosition.scale;
tile.lastDraw = mRedrawCnt;
// mDrawCount is used to calculation z offset.
// (used for depth clipping)
setMatrix(tile, div, mDrawCount++);
glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id);
// GLES20.glPolygonOffset(0, mDrawCount);
LineLayer ll = tile.lineLayers;
PolygonLayer pl = tile.polygonLayers;
@ -955,15 +978,15 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
pl = PolygonLayers.drawPolygons(pl, lnext, mMVPMatrix, z, s, !clipped);
if (!clipped) {
clipped = true;
}
clipped = true;
} else {
// XXX nastay
// XXX nasty
if (!clipped) {
PolygonLayers.drawPolygons(null, 0, mMVPMatrix, z, s, true);
clipped = true;
}
glEnable(GL_BLEND);
ll = LineLayers.drawLines(tile, ll, pnext, mMVPMatrix, div, z, s);
@ -1081,14 +1104,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
// Set up textures
TextRenderer.init(numTiles);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// glDisable(GLES20.GL_DEPTH_TEST);
// glDepthMask(false);
// GLES20.glDepthRangef(1, 0);
// GLES20.glClearDepthf(0);
glDisable(GL_DITHER);
// glDisable(GL_DITHER);
if (mClearColor != null) {
glClearColor(mClearColor[0], mClearColor[1],
@ -1096,12 +1112,17 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
} else {
glClearColor(0.98f, 0.98f, 0.97f, 1.0f);
}
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
glScissor(0, 0, mWidth, mHeight);
glBlendFunc(GLES20.GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
GlUtils.checkGlError("onSurfaceChanged");
mMapView.redrawTiles();
}
@ -1127,10 +1148,10 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
mFillCoords[6] = max;
mFillCoords[7] = min;
int i[] = new int[1];
// int i[] = new int[1];
// GLES20.glGetIntegerv(GLES20.GL_, i, 0);
Log.d(TAG, " >>>> " + i[0]);
// Log.d(TAG, " >>>> " + i[0]);
LineLayers.init();
PolygonLayers.init();
}

View File

@ -25,7 +25,6 @@ import static android.opengl.GLES20.glColorMask;
import static android.opengl.GLES20.glDisable;
import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.GLES20.glEnable;
import static android.opengl.GLES20.glEnableVertexAttribArray;
import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glGetUniformLocation;
import static android.opengl.GLES20.glStencilFunc;
@ -82,7 +81,7 @@ class PolygonLayers {
// do not modify stencil buffer
glStencilMask(0);
// GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL);
glEnable(GLES20.GL_DEPTH_TEST);
for (int c = 0; c < count; c++) {
PolygonLayer l = mFillPolys[c];
@ -90,7 +89,7 @@ class PolygonLayers {
float alpha = 1.0f;
if (l.area.fade >= zoom || l.area.color[3] != 1.0) {
// draw alpha blending, fade in/out
if (l.area.fade >= zoom) {
alpha = (scale > 1.3f ? scale : 1.3f) - alpha;
if (alpha > 1.0f)
@ -104,9 +103,13 @@ class PolygonLayers {
blend = true;
}
glUniform4f(hPolygonColor,
l.area.color[0], l.area.color[1], l.area.color[2], alpha);
l.area.color[0] * alpha,
l.area.color[1] * alpha,
l.area.color[2] * alpha,
alpha);
} else if (l.area.blend == zoom) {
// fade in/out
alpha = scale - 1.0f;
if (alpha > 1.0f)
alpha = 1.0f;
@ -118,6 +121,7 @@ class PolygonLayers {
l.area.color[1] * (1 - alpha) + l.area.blendColor[1] * alpha,
l.area.color[2] * (1 - alpha) + l.area.blendColor[2] * alpha, 1);
} else {
// draw solid
if (blend) {
glDisable(GL_BLEND);
blend = false;
@ -144,7 +148,7 @@ class PolygonLayers {
int cnt = 0;
glUseProgram(polygonProgram);
glEnableVertexAttribArray(hPolygonVertexPosition);
GLES20.glEnableVertexAttribArray(hPolygonVertexPosition);
glVertexAttribPointer(hPolygonVertexPosition, 2,
GLES20.GL_SHORT, false, 0,
@ -177,9 +181,12 @@ class PolygonLayers {
// clear stencilbuffer (tile region)
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
// draw depth clipper
if (first) {
// draw clip-region into depth buffer
GLES20.glDepthMask(true);
// to prevent overdraw gl_less restricts
// the clip to the area where no other
// tile was drawn
GLES20.glDepthFunc(GLES20.GL_LESS);
}
@ -193,6 +200,7 @@ class PolygonLayers {
// stencil op for stencil method polygon drawing
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
glDisable(GLES20.GL_DEPTH_TEST);
}
mFillPolys[cnt] = l;
@ -218,7 +226,6 @@ class PolygonLayers {
// required on GalaxyII, Android 2.3.3 (cant just VAA enable once...)
GLES20.glDisableVertexAttribArray(hPolygonVertexPosition);
return l;
}

View File

@ -20,17 +20,35 @@ class Shaders {
final static String lineVertexShader = ""
+ "precision mediump float;"
+ "uniform mat4 mvp;"
+ "attribute vec4 a_position;"
+ "attribute vec2 a_position;"
+ "attribute vec2 a_st;"
+ "varying vec2 v_st;"
+ "uniform float u_width;"
+ "const float dscale = 8.0/1000.0;"
+ "const float dscale = 8.0/2048.0;"
+ "void main() {"
+ " vec2 dir = dscale * u_width * a_position.zw;"
+ " gl_Position = mvp * vec4(a_position.xy + dir, 0.0,1.0);"
+ " v_st = u_width * a_st;"
// scale extrusion to line u_width pixel
// just ignore the two most insignificant bits of a_st :)
+ " vec2 dir = dscale * u_width * a_st;"
+ " gl_Position = mvp * vec4(a_position + dir, 0.0,1.0);"
// last two bits of a_st hold the texture coordinates
// TODO use bit operations when available!
+ " v_st = u_width * (abs(mod(a_st,4.0)) - 1.0);"
+ "}";
// final static String lineVertexShader = ""
// + "precision mediump float;"
// + "uniform mat4 mvp;"
// + "attribute vec4 a_position;"
// + "attribute vec2 a_st;"
// + "varying vec2 v_st;"
// + "uniform float u_width;"
// + "const float dscale = 8.0/1000.0;"
// + "void main() {"
// + " vec2 dir = dscale * u_width * a_position.zw;"
// + " gl_Position = mvp * vec4(a_position.xy + dir, 0.0,1.0);"
// + " v_st = u_width * a_st;"
// + "}";
final static String lineFragmentShader = ""
+ "precision mediump float;"
+ "uniform float u_wscale;"
@ -45,7 +63,12 @@ class Shaders {
+ " len = abs(v_st.s);"
+ " else "
+ " len = length(v_st);"
+ " color.a *= smoothstep(zero, u_wscale, u_width - len);"
// fade to alpha. u_wscale is the width in pixel which should be faded,
// u_width - len the position of this fragment on the perpendicular to the line
+ "color *= smoothstep(zero, u_wscale, u_width - len);"
+ "if (color.a < 0.02)"
+ " discard;"
+ " else"
+ " gl_FragColor = color;"
+ "}";

View File

@ -16,11 +16,11 @@
package org.mapsforge.android.glrenderer;
class VertexBufferObject {
final int id;
int id;
int size;
VertexBufferObject(int id) {
this.id = id;
size = 0;
}
}
}

View File

@ -1,240 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mapsforge.android.input;
import org.mapsforge.android.MapView;
import org.mapsforge.android.utils.PausableThread;
import android.os.SystemClock;
import android.view.KeyEvent;
import android.view.MotionEvent;
/**
* A MapMover moves the map horizontally and vertically at a configurable speed. It runs in a separate thread to avoid
* blocking the UI thread.
*/
public class MapMover extends PausableThread implements KeyEvent.Callback {
private static final int DEFAULT_MOVE_SPEED_FACTOR = 10;
private static final int FRAME_LENGTH_IN_MS = 15;
private static final float MOVE_SPEED = 0.2f;
private static final String THREAD_NAME = "MapMover";
private static final float TRACKBALL_MOVE_SPEED_FACTOR = 40;
private final MapView mMapView;
private float mMoveSpeedFactor;
private float mMoveX;
private float mMoveY;
private long mTimePrevious;
/**
* @param mapView
* the MapView which should be moved by this MapMover.
*/
public MapMover(MapView mapView) {
super();
mMapView = mapView;
mMoveSpeedFactor = DEFAULT_MOVE_SPEED_FACTOR;
}
/**
* @return the move speed factor, used for trackball and keyboard events.
*/
public float getMoveSpeedFactor() {
return mMoveSpeedFactor;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent keyEvent) {
if (!mMapView.isClickable()) {
return false;
}
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
moveLeft();
return true;
} else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
moveRight();
return true;
} else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
moveUp();
return true;
} else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
moveDown();
return true;
}
return false;
}
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent keyEvent) {
return false;
}
@Override
public boolean onKeyMultiple(int keyCode, int count, KeyEvent keyEvent) {
return false;
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent keyEvent) {
if (!mMapView.isClickable()) {
return false;
}
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
mMoveX = 0;
return true;
} else if (keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
mMoveY = 0;
return true;
}
return false;
}
/**
* @param motionEvent
* a trackball event which should be handled.
* @return true if the event was handled, false otherwise.
*/
public boolean onTrackballEvent(MotionEvent motionEvent) {
if (!mMapView.isClickable()) {
return false;
}
if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
float mapMoveX = motionEvent.getX() * TRACKBALL_MOVE_SPEED_FACTOR * getMoveSpeedFactor();
float mapMoveY = motionEvent.getY() * TRACKBALL_MOVE_SPEED_FACTOR * getMoveSpeedFactor();
// mapView.getFrameBuffer().matrixPostTranslate(mapMoveX,
// mapMoveY);
mMapView.getMapPosition().moveMap(mapMoveX, mapMoveY);
mMapView.redrawTiles();
return true;
}
return false;
}
/**
* Sets the move speed factor of the map, used for trackball and keyboard events.
*
* @param moveSpeedFactor
* the factor by which the move speed of the map will be multiplied.
* @throws IllegalArgumentException
* if the new move speed factor is negative.
*/
public void setMoveSpeedFactor(float moveSpeedFactor) {
if (moveSpeedFactor < 0) {
throw new IllegalArgumentException();
}
mMoveSpeedFactor = moveSpeedFactor;
}
/**
* Stops moving the map completely.
*/
public void stopMove() {
mMoveX = 0;
mMoveY = 0;
}
private void moveDown() {
if (mMoveY > 0) {
// stop moving the map vertically
mMoveY = 0;
} else if (mMoveY == 0) {
// start moving the map
mMoveY = -MOVE_SPEED * mMoveSpeedFactor;
mTimePrevious = SystemClock.uptimeMillis();
synchronized (this) {
notify();
}
}
}
private void moveLeft() {
if (mMoveX < 0) {
// stop moving the map horizontally
mMoveX = 0;
} else if (mMoveX == 0) {
// start moving the map
mMoveX = MOVE_SPEED * mMoveSpeedFactor;
mTimePrevious = SystemClock.uptimeMillis();
synchronized (this) {
notify();
}
}
}
private void moveRight() {
if (mMoveX > 0) {
// stop moving the map horizontally
mMoveX = 0;
} else if (mMoveX == 0) {
// start moving the map
mMoveX = -MOVE_SPEED * mMoveSpeedFactor;
mTimePrevious = SystemClock.uptimeMillis();
synchronized (this) {
notify();
}
}
}
private void moveUp() {
if (mMoveY < 0) {
// stop moving the map vertically
mMoveY = 0;
} else if (mMoveY == 0) {
// start moving the map
mMoveY = MOVE_SPEED * mMoveSpeedFactor;
mTimePrevious = SystemClock.uptimeMillis();
synchronized (this) {
notify();
}
}
}
@Override
protected void afterPause() {
mTimePrevious = SystemClock.uptimeMillis();
}
@Override
protected void doWork() throws InterruptedException {
// calculate the time difference to previous call
long timeCurrent = SystemClock.uptimeMillis();
long timeElapsed = timeCurrent - mTimePrevious;
mTimePrevious = timeCurrent;
// add the movement to the transformation matrices
// mapView.getFrameBuffer().matrixPostTranslate(timeElapsed *
// moveX, timeElapsed * moveY);
// move the map and the overlays
mMapView.getMapPosition().moveMap(timeElapsed * mMoveX, timeElapsed * mMoveY);
mMapView.redrawTiles();
sleep(FRAME_LENGTH_IN_MS);
}
@Override
protected String getThreadName() {
return THREAD_NAME;
}
@Override
protected boolean hasWork() {
return mMoveX != 0 || mMoveY != 0;
}
}

View File

@ -1,121 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mapsforge.android.input;
import org.mapsforge.android.MapView;
import org.mapsforge.android.utils.PausableThread;
import android.os.SystemClock;
/**
* A ZoomAnimator handles the zoom-in and zoom-out animations of the corresponding MapView. It runs in a separate thread
* to avoid blocking the UI thread.
*/
public class ZoomAnimator extends PausableThread {
private static final int DEFAULT_DURATION = 250;
private static final int FRAME_LENGTH_IN_MS = 15;
private static final String THREAD_NAME = "ZoomAnimator";
private boolean mExecuteAnimation;
private final MapView mMapView;
// private float mPivotX;
// private float mPivotY;
private float mScaleFactorApplied;
private long mTimeStart;
private float mZoomDifference;
private float mZoomEnd;
private float mZoomStart;
/**
* @param mapView
* the MapView whose zoom level changes should be animated.
*/
public ZoomAnimator(MapView mapView) {
super();
mMapView = mapView;
}
/**
* @return true if the ZoomAnimator is working, false otherwise.
*/
public boolean isExecuting() {
return mExecuteAnimation;
}
/**
* Sets the parameters for the zoom animation.
*
* @param zoomStart
* the zoom factor at the begin of the animation.
* @param zoomEnd
* the zoom factor at the end of the animation.
* @param pivotX
* the x coordinate of the animation center.
* @param pivotY
* the y coordinate of the animation center.
*/
public void setParameters(float zoomStart, float zoomEnd, float pivotX, float pivotY) {
mZoomStart = zoomStart;
mZoomEnd = zoomEnd;
// mPivotX = pivotX;
// mPivotY = pivotY;
}
/**
* Starts a zoom animation with the current parameters.
*/
public void startAnimation() {
mZoomDifference = mZoomEnd - mZoomStart;
mScaleFactorApplied = mZoomStart;
mExecuteAnimation = true;
mTimeStart = SystemClock.uptimeMillis();
synchronized (this) {
notify();
}
}
@Override
protected void doWork() throws InterruptedException {
// calculate the elapsed time
long timeElapsed = SystemClock.uptimeMillis() - mTimeStart;
float timeElapsedPercent = Math.min(1, timeElapsed / (float) DEFAULT_DURATION);
// calculate the zoom and scale values at the current moment
float currentZoom = mZoomStart + timeElapsedPercent * mZoomDifference;
float scaleFactor = currentZoom / mScaleFactorApplied;
mScaleFactorApplied *= scaleFactor;
// mapView.getFrameBuffer().matrixPostScale(scaleFactor, scaleFactor,
// pivotX, pivotY);
// check if the animation time is over
if (timeElapsed >= DEFAULT_DURATION) {
mExecuteAnimation = false;
mMapView.redrawTiles();
} else {
mMapView.postInvalidate();
sleep(FRAME_LENGTH_IN_MS);
}
}
@Override
protected String getThreadName() {
return THREAD_NAME;
}
@Override
protected boolean hasWork() {
return mExecuteAnimation;
}
}

View File

@ -114,17 +114,17 @@ public final class Area extends RenderInstruction {
// }
color = new float[4];
color[0] = (fill >> 16 & 0xff) / 255.0f;
color[1] = (fill >> 8 & 0xff) / 255.0f;
color[2] = (fill >> 0 & 0xff) / 255.0f;
color[3] = (fill >> 24 & 0xff) / 255.0f;
color[0] = (fill >> 16 & 0xff) / 255.0f * color[3];
color[1] = (fill >> 8 & 0xff) / 255.0f * color[3];
color[2] = (fill >> 0 & 0xff) / 255.0f * color[3];
if (blend > 0) {
blendColor = new float[4];
blendColor[0] = (blendFill >> 16 & 0xff) / 255.0f;
blendColor[1] = (blendFill >> 8 & 0xff) / 255.0f;
blendColor[2] = (blendFill >> 0 & 0xff) / 255.0f;
blendColor[3] = (blendFill >> 24 & 0xff) / 255.0f;
blendColor[0] = (blendFill >> 16 & 0xff) / 255.0f * blendColor[3];
blendColor[1] = (blendFill >> 8 & 0xff) / 255.0f * blendColor[3];
blendColor[2] = (blendFill >> 0 & 0xff) / 255.0f * blendColor[3];
} else {
blendColor = null;
}

View File

@ -188,10 +188,10 @@ public final class Line extends RenderInstruction {
this.cap = strokeLinecap;
color = new float[4];
color[0] = (stroke >> 16 & 0xff) / 255.0f;
color[1] = (stroke >> 8 & 0xff) / 255.0f;
color[2] = (stroke >> 0 & 0xff) / 255.0f;
color[3] = (stroke >> 24 & 0xff) / 255.0f;
color[0] = (stroke >> 16 & 0xff) / 255.0f * color[3];
color[1] = (stroke >> 8 & 0xff) / 255.0f * color[3];
color[2] = (stroke >> 0 & 0xff) / 255.0f * color[3];
this.width = strokeWidth;
this.level = level;

View File

@ -25,9 +25,9 @@ public class GlConfigChooser implements GLSurfaceView.EGLConfigChooser {
// Try to find a normal multisample configuration first.
int[] configSpec = {
EGL10.EGL_RED_SIZE, 8,
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_RED_SIZE, 5,
EGL10.EGL_GREEN_SIZE, 6,
EGL10.EGL_BLUE_SIZE, 5,
EGL10.EGL_ALPHA_SIZE, 0,
EGL10.EGL_DEPTH_SIZE, 24,
// Requires that setEGLContextClientVersion(2) is called on the view.
@ -132,15 +132,16 @@ public class GlConfigChooser implements GLSurfaceView.EGLConfigChooser {
*/
return String.format("EGLConfig rgba=%d%d%d%d depth=%d stencil=%d",
new Integer(r), new Integer(g),
new Integer(b), new Integer(a), new Integer(d), new Integer(s))
Integer.valueOf(r), Integer.valueOf(g),
Integer.valueOf(b), Integer.valueOf(a), Integer.valueOf(d),
Integer.valueOf(s))
+ " native="
+ findConfigAttrib(egl, display, config, EGL10.EGL_NATIVE_RENDERABLE, 0)
+ " buffer="
+ findConfigAttrib(egl, display, config, EGL10.EGL_BUFFER_SIZE, 0)
+ String.format(
" caveat=0x%04x",
new Integer(findConfigAttrib(egl, display, config,
Integer.valueOf(findConfigAttrib(egl, display, config,
EGL10.EGL_CONFIG_CAVEAT, 0)));
}