diff --git a/src/org/oscim/generator/TileGenerator.java b/src/org/oscim/generator/TileGenerator.java
index 846a0250..fd1084ef 100644
--- a/src/org/oscim/generator/TileGenerator.java
+++ b/src/org/oscim/generator/TileGenerator.java
@@ -16,6 +16,8 @@ package org.oscim.generator;
import static org.oscim.generator.JobTile.STATE_NONE;
+import java.util.Arrays;
+
import org.oscim.core.MercatorProjection;
import org.oscim.core.Tag;
import org.oscim.core.Tile;
@@ -27,6 +29,7 @@ import org.oscim.renderer.layer.ExtrusionLayer;
import org.oscim.renderer.layer.Layer;
import org.oscim.renderer.layer.Layers;
import org.oscim.renderer.layer.LineLayer;
+import org.oscim.renderer.layer.LineTexLayer;
import org.oscim.renderer.layer.PolygonLayer;
import org.oscim.renderer.layer.TextItem;
import org.oscim.theme.IRenderCallback;
@@ -132,7 +135,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
*/
public TileGenerator(MapView mapView) {
// mMapView = mapView;
- mClipper = new LineClipper(0,0,Tile.TILE_SIZE, Tile.TILE_SIZE, true);
+ mClipper = new LineClipper(0, 0, Tile.TILE_SIZE, Tile.TILE_SIZE, true);
}
public void cleanup() {
@@ -254,6 +257,8 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
mTagHouseNr = tags[i];
tags[i] = mTagEmptyHouseNr;
} else if (mTile.zoomLevel >= 17 &&
+ // FIXME, allow overlays to intercept
+ // this, or use a theme option for this
key == Tag.TAG_KEY_BUILDING) {
mRenderBuildingModel = true;
}
@@ -270,38 +275,12 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
mTagName = null;
mTagHouseNr = null;
- //if (mMapProjection != null) {
- // long x = mTile.pixelX;
- // long y = mTile.pixelY + Tile.TILE_SIZE;
- // long z = Tile.TILE_SIZE << mTile.zoomLevel;
- //
- // double divx, divy;
- // long dx = (x - (z >> 1));
- // long dy = (y - (z >> 1));
- //
- // if (mMapProjection == WebMercator.NAME) {
- // double div = WebMercator.f900913 / (z >> 1);
- // // divy = f900913 / (z >> 1);
- // mPoiX = (float) (longitude / div - dx);
- // mPoiY = (float) (latitude / div + dy);
- // } else {
- // divx = 180000000.0 / (z >> 1);
- // divy = z / PIx4;
- // mPoiX = (float) (longitude / divx - dx);
- // double sinLat = Math.sin(latitude * PI180);
- // mPoiY = (float) (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy);
- // return;
- // }
- //} else {
mPoiX = longitude;
mPoiY = latitude;
- //}
// remove tags that should not be cached in Rendertheme
filterTags(tags);
- // Log.d(TAG, "renderPointOfInterest: " + mTagName);
- // mNodeRenderInstructions =
TileGenerator.renderTheme.matchNode(this, tags, mTile.zoomLevel);
}
@@ -338,8 +317,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
private void debugUnmatched(boolean closed, Tag[] tags) {
- Log.d(TAG, "way not matched: " + tags[0] + " "
- + (tags.length > 1 ? tags[1] : "") + " " + closed);
+ Log.d(TAG, "DBG way not matched: " + closed + " " + Arrays.deepToString(tags));
mTagName = new Tag("name", tags[0].key + ":" + tags[0].value, false);
@@ -366,37 +344,62 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
// ----------------- RenderThemeCallback -----------------
@Override
public void renderWay(Line line, int level) {
- // projectToTile();
+ // TODO projectToTile();
- if (line.outline && mCurLineLayer == null) {
- // TODO fix this in RenderTheme
- Log.e(TAG, "theme issue, cannot add outline: line must come before outline!");
- return;
- }
int numLayer = (mDrawingLayer * 2) + level;
- LineLayer lineLayer = (LineLayer) mLayers.getLayer(numLayer, Layer.LINE);
- if (lineLayer == null)
- return;
-
- if (lineLayer.line == null) {
- lineLayer.line = line;
-
- float w = line.width;
- if (!line.fixed) {
- w *= mStrokeScale;
- w *= mProjectionScaleFactor;
+ if (line.stipple == 0) {
+ if (line.outline && mCurLineLayer == null) {
+ // FIXME in RenderTheme
+ Log.e(TAG, "BUG in theme: line must come before outline!");
+ return;
}
- lineLayer.width = w;
- }
- if (line.outline) {
- lineLayer.addOutline(mCurLineLayer);
- return;
- }
+ LineLayer lineLayer = (LineLayer)
+ mLayers.getLayer(numLayer, Layer.LINE);
- lineLayer.addLine(mCoords, mIndices, mClosed);
- mCurLineLayer = lineLayer;
+ if (lineLayer == null)
+ return;
+
+ if (lineLayer.line == null) {
+ lineLayer.line = line;
+
+ float w = line.width;
+ if (!line.fixed) {
+ w *= mStrokeScale;
+ w *= mProjectionScaleFactor;
+ }
+ lineLayer.width = w;
+ }
+
+ if (line.outline) {
+ lineLayer.addOutline(mCurLineLayer);
+ return;
+ }
+
+ lineLayer.addLine(mCoords, mIndices, mClosed);
+ mCurLineLayer = lineLayer;
+ } else {
+ LineTexLayer lineLayer = (LineTexLayer)
+ mLayers.getLayer(numLayer, Layer.TEXLINE);
+
+ if (lineLayer == null)
+ return;
+
+ if (lineLayer.line == null) {
+ lineLayer.line = line;
+
+ float w = line.width;
+ if (!line.fixed) {
+ w *= mStrokeScale;
+ w *= mProjectionScaleFactor;
+ }
+ lineLayer.width = w;
+ }
+
+
+ lineLayer.addLine(mCoords, mIndices);
+ }
}
@Override
@@ -480,8 +483,8 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
int length = mIndices[i];
if (length < 4)
break;
- mLabels = WayDecorator.renderText(mClipper,mCoords, mTagName.value, text,
- offset, length, mLabels);
+ mLabels = WayDecorator.renderText(mClipper, mCoords, mTagName.value, text,
+ offset, length, mLabels);
offset += length;
}
}
@@ -520,6 +523,31 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
// // TODO move this to Projection classes
//
+
+ //if (mMapProjection != null) {
+ // long x = mTile.pixelX;
+ // long y = mTile.pixelY + Tile.TILE_SIZE;
+ // long z = Tile.TILE_SIZE << mTile.zoomLevel;
+ //
+ // double divx, divy;
+ // long dx = (x - (z >> 1));
+ // long dy = (y - (z >> 1));
+ //
+ // if (mMapProjection == WebMercator.NAME) {
+ // double div = WebMercator.f900913 / (z >> 1);
+ // // divy = f900913 / (z >> 1);
+ // mPoiX = (float) (longitude / div - dx);
+ // mPoiY = (float) (latitude / div + dy);
+ // } else {
+ // divx = 180000000.0 / (z >> 1);
+ // divy = z / PIx4;
+ // mPoiX = (float) (longitude / divx - dx);
+ // double sinLat = Math.sin(latitude * PI180);
+ // mPoiY = (float) (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy);
+ // return;
+ // }
+ //} else {
+
// private String mMapProjection;
// private static final double PI180 = (Math.PI / 180) / 1000000.0;
// private static final double PIx4 = Math.PI * 4;
diff --git a/src/org/oscim/renderer/BaseMap.java b/src/org/oscim/renderer/BaseMap.java
index dcb3a446..45205c77 100644
--- a/src/org/oscim/renderer/BaseMap.java
+++ b/src/org/oscim/renderer/BaseMap.java
@@ -28,7 +28,8 @@ import android.opengl.GLES20;
import android.opengl.Matrix;
/**
- * This class is for rendering the Line- and PolygonLayers of visible MapTiles. For
+ * This class is for rendering the Line- and PolygonLayers of visible MapTiles.
+ * For
* visible tiles that do not have data available yet its parent in children
* tiles are rendered when available.
*
@@ -107,12 +108,12 @@ public class BaseMap {
if (t.holder != null)
t = t.holder;
- if (t.layers == null || t.vbo == null) {
+ if (t.layers == null || t.layers.vbo == null) {
//Log.d(TAG, "missing data " + (t.layers == null) + " " + (t.vbo == null));
return;
}
- GLES20.glBindBuffer(GL_ARRAY_BUFFER, t.vbo.id);
+ GLES20.glBindBuffer(GL_ARRAY_BUFFER, t.layers.vbo.id);
// place tile relative to map position
float div = FastMath.pow(tile.zoomLevel - pos.zoomLevel);
@@ -135,8 +136,9 @@ public class BaseMap {
int simpleShader = (pos.tilt < 1 ? 1 : 0);
boolean clipped = false;
+ boolean lineTexture = true;
- for (Layer l = t.layers.layers; l != null;) {
+ for (Layer l = t.layers.baseLayers; l != null;) {
switch (l.type) {
case Layer.POLYGON:
l = PolygonRenderer.draw(pos, l, mvp, !clipped, true);
@@ -144,16 +146,38 @@ public class BaseMap {
break;
case Layer.LINE:
+ //if (!lineTexture) {
+ LineRenderer.beginLines();
+ // lineTexture = true;
+ //}
if (!clipped) {
+ // draw stencil buffer clip region
PolygonRenderer.draw(pos, null, mvp, true, true);
clipped = true;
}
- l = LineRenderer.draw(pos, l, mvp, div, simpleShader,
- t.layers.lineOffset);
+ l = LineRenderer.draw(t.layers, l, pos, mvp, div, simpleShader);
+
break;
+
+ case Layer.TEXLINE:
+ LineRenderer.endLines();
+
+ if (!clipped) {
+ // draw stencil buffer clip region
+ PolygonRenderer.draw(pos, null, mvp, true, true);
+ clipped = true;
+ }
+ l = LineTexRenderer.draw(t.layers, l, pos, mvp, div);
+ lineTexture = false;
+ break;
+
+ default:
+ // just in case
+ l = l.next;
}
}
+ // clear clip-region and could also draw 'fade-effect'
PolygonRenderer.drawOver(mvp);
}
diff --git a/src/org/oscim/renderer/GLRenderer.java b/src/org/oscim/renderer/GLRenderer.java
index f2c8348e..7d10e19c 100644
--- a/src/org/oscim/renderer/GLRenderer.java
+++ b/src/org/oscim/renderer/GLRenderer.java
@@ -74,7 +74,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// bytes currently loaded in VBOs
private static int mBufferMemoryUsage;
-
private static float[] mTileCoords = new float[8];
private static float[] mDebugCoords = new float[8];
@@ -211,10 +210,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private static int uploadCnt = 0;
- public static boolean uploadLayers(Layers layers, BufferObject vbo, int newSize,
+ public static boolean uploadLayers(Layers layers, int newSize,
boolean addFill) {
- GLES20.glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
+ GLES20.glBindBuffer(GL_ARRAY_BUFFER, layers.vbo.id);
// add fill coordinates
if (addFill)
@@ -241,23 +240,23 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (newSize != sbuf.remaining()) {
Log.d(TAG, "wrong size: "
- + newSize + " "
- + sbuf.position() + " "
- + sbuf.limit() + " "
- + sbuf.remaining());
+ + " new size: " + newSize
+ + " buffer pos: " + sbuf.position()
+ + " buffer limit: " + sbuf.limit()
+ + " buffer fill: " + sbuf.remaining());
return false;
}
newSize *= SHORT_BYTES;
// reuse memory allocated for vbo when possible and allocated
// memory is less then four times the new data
- if (vbo.size > newSize && vbo.size < newSize * 4
+ if (layers.vbo.size > newSize && layers.vbo.size < newSize * 4
&& mBufferMemoryUsage < LIMIT_BUFFERS) {
GLES20.glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, sbuf);
} else {
- mBufferMemoryUsage += newSize - vbo.size;
- vbo.size = newSize;
- GLES20.glBufferData(GL_ARRAY_BUFFER, vbo.size, sbuf, GL_DYNAMIC_DRAW);
+ mBufferMemoryUsage += newSize - layers.vbo.size;
+ layers.vbo.size = newSize;
+ GLES20.glBufferData(GL_ARRAY_BUFFER, layers.vbo.size, sbuf, GL_DYNAMIC_DRAW);
}
return true;
@@ -272,15 +271,16 @@ public class GLRenderer implements GLSurfaceView.Renderer {
int newSize = tile.layers.getSize();
if (newSize > 0) {
- if (tile.vbo == null)
- tile.vbo = BufferObject.get(newSize);
+ if (tile.layers.vbo == null)
+ tile.layers.vbo = BufferObject.get(newSize);
- if (!uploadLayers(tile.layers, tile.vbo, newSize, true)) {
+ if (!uploadLayers(tile.layers, newSize, true)) {
Log.d(TAG, "BUG uploadTileData " + tile + " failed!");
+
+ BufferObject.release(tile.layers.vbo);
+ tile.layers.vbo = null;
tile.layers.clear();
tile.layers = null;
- BufferObject.release(tile.vbo);
- tile.vbo = null;
}
}
}
@@ -376,7 +376,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
MapPosition pos = mMapPosition;
float[] coords = mTileCoords;
boolean changed;
- synchronized(mMapViewPosition){
+ synchronized (mMapViewPosition) {
changed = mMapViewPosition.getMapPosition(pos);
mMapViewPosition.getMapViewProjection(coords);
mMapViewPosition.getMatrix(mMatrices.view, null, mMatrices.viewproj);
@@ -621,7 +621,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// String ext = GLES20.glGetString(GLES20.GL_EXTENSIONS);
// Log.d(TAG, "Extensions: " + ext);
+ // classes that require GL context for initialization
LineRenderer.init();
+ LineTexRenderer.init();
PolygonRenderer.init();
TextureRenderer.init();
TextureObject.init(10);
diff --git a/src/org/oscim/renderer/LineRenderer.java b/src/org/oscim/renderer/LineRenderer.java
index 10c1e271..c002525a 100644
--- a/src/org/oscim/renderer/LineRenderer.java
+++ b/src/org/oscim/renderer/LineRenderer.java
@@ -27,6 +27,7 @@ import static android.opengl.GLES20.glVertexAttribPointer;
import org.oscim.core.MapPosition;
import org.oscim.generator.TileGenerator;
import org.oscim.renderer.layer.Layer;
+import org.oscim.renderer.layer.Layers;
import org.oscim.renderer.layer.LineLayer;
import org.oscim.theme.renderinstruction.Line;
import org.oscim.utils.GlUtils;
@@ -34,10 +35,6 @@ import org.oscim.utils.GlUtils;
import android.opengl.GLES20;
import android.util.Log;
-/**
- * @author Hannes Janetzek
- */
-
public final class LineRenderer {
private final static String TAG = LineRenderer.class.getName();
@@ -97,6 +94,7 @@ public final class LineRenderer {
}
mTexID = GlUtils.loadTexture(pixel, 128, 128, GLES20.GL_ALPHA,
+ GLES20.GL_NEAREST, GLES20.GL_NEAREST,
GLES20.GL_MIRRORED_REPEAT, GLES20.GL_MIRRORED_REPEAT);
return true;
@@ -110,13 +108,13 @@ public final class LineRenderer {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
- public static Layer draw(MapPosition pos, Layer layer, float[] matrix, float div,
- int mode, int bufferOffset) {
+ public static Layer draw(Layers layers, Layer curLayer, MapPosition pos,
+ float[] matrix, float div, int mode) {
int zoom = pos.zoomLevel;
float scale = pos.scale;
- if (layer == null)
+ if (curLayer == null)
return null;
GLState.blend(true);
@@ -131,13 +129,13 @@ public final class LineRenderer {
GLState.enableVertexArrays(hLineVertexPosition[mode], -1);
glVertexAttribPointer(hLineVertexPosition[mode], 4, GL_SHORT,
- false, 0, bufferOffset + LINE_VERTICES_DATA_POS_OFFSET);
+ false, 0, layers.lineOffset + LINE_VERTICES_DATA_POS_OFFSET);
glUniformMatrix4fv(hLineMatrix[mode], 1, false, matrix, 0);
- // line scale factor for non fixed lines: within a zoom-
- // level lines would be scaled by the factor 2 via projection.
- // though lines should only scale by sqrt(2). this is achieved
+ // Line scale factor for non fixed lines: Within a zoom-
+ // level lines would be scaled by the factor 2 by view-matrix.
+ // Though lines should only scale by sqrt(2). This is achieved
// by inverting scaling of extrusion vector with: width/sqrt(s).
// within one zoom-level: 1 <= s <= 2
float s = scale / div;
@@ -158,7 +156,7 @@ public final class LineRenderer {
// dont increase scale when max is reached
boolean strokeMaxZoom = zoom > TileGenerator.STROKE_MAX_ZOOM_LEVEL;
- Layer l = layer;
+ Layer l = curLayer;
for (; l != null && l.type == Layer.LINE; l = l.next) {
LineLayer ll = (LineLayer) l;
Line line = ll.line;
@@ -187,7 +185,7 @@ public final class LineRenderer {
} else {
width = ll.width / s + o.width / lineScale;
- // check min size for outline
+ // check min-size for outline
if (o.line.min > 0 && o.width * lineScale < o.line.min * 2)
continue;
}
@@ -223,7 +221,9 @@ public final class LineRenderer {
// line width increases by sqrt(2.2).
width = ll.width / lineScale;
- if (ll.line.min > 0 && ll.width * lineScale < ll.line.min * 2)
+ // min-size hack to omit outline when line becomes
+ // very thin
+ if ((ll.line.min > 0) && (ll.width * lineScale < ll.line.min * 2))
width = (ll.width - 0.2f) / lineScale;
}
@@ -262,7 +262,6 @@ public final class LineRenderer {
+ "attribute vec4 a_pos;"
+ "uniform float u_mode;"
+ "varying vec2 v_st;"
- + "varying vec2 v_mode;"
+ "void main() {"
// scale extrusion to u_width pixel
// just ignore the two most insignificant bits of a_st :)
@@ -271,26 +270,24 @@ public final class LineRenderer {
// last two bits of a_st hold the texture coordinates
// ..maybe one could wrap texture so that `abs` is not required
+ " v_st = abs(mod(dir, 4.0)) - 1.0;"
- + " v_mode = vec2(1.0 - u_mode, u_mode);"
+ "}";
private final static String lineSimpleFragmentShader = ""
+ "precision mediump float;"
+ "uniform sampler2D tex;"
+ "uniform float u_wscale;"
+ + "uniform float u_mode;"
+ "uniform vec4 u_color;"
+ "varying vec2 v_st;"
- + "varying vec2 v_mode;"
+ "void main() {"
//+ " float len;"
- // some say one should not use conditionals
- // (FIXME currently required as overlay line renderers dont load the texture)
+ // (currently required as overlay line renderers dont load the texture)
//+ " if (u_mode == 0)"
//+ " len = abs(v_st.s);"
//+ " else"
//+ " len = texture2D(tex, v_st).a;"
- // one trick to avoid branching, need to check performance
- + " float len = max(v_mode[0] * abs(v_st.s), v_mode[1] * texture2D(tex, v_st).a);"
+ // this avoids branching, need to check performance
+ + " float len = max((1.0 - u_mode) * abs(v_st.s), u_mode * texture2D(tex, v_st).a);"
// interpolate alpha between: 0.0 < 1.0 - len < u_wscale
// where wscale is 'filter width' / 'line width' and 0 <= len <= sqrt(2)
+ " gl_FragColor = u_color * smoothstep(0.0, u_wscale, 1.0 - len);"
diff --git a/src/org/oscim/renderer/LineTexRenderer.java b/src/org/oscim/renderer/LineTexRenderer.java
new file mode 100644
index 00000000..07217d98
--- /dev/null
+++ b/src/org/oscim/renderer/LineTexRenderer.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2013 Hannes Janetzek
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.renderer;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ShortBuffer;
+
+import org.oscim.core.MapPosition;
+import org.oscim.renderer.layer.Layer;
+import org.oscim.renderer.layer.Layers;
+import org.oscim.renderer.layer.LineTexLayer;
+import org.oscim.utils.GlUtils;
+
+import android.opengl.GLES20;
+import android.util.Log;
+
+public class LineTexRenderer {
+ private final static String TAG = LineTexRenderer.class.getName();
+
+ private static int shader;
+ private static int hVertexPosition0;
+ private static int hVertexPosition1;
+ private static int hVertexLength0;
+ private static int hVertexLength1;
+ private static int hVertexFlip;
+ private static int hMatrix;
+ private static int hTexColor;
+ private static int hBgColor;
+ private static int hScale;
+
+ private static int mIndicesBufferID;
+ private static int mVertexFlipID;
+
+ // draw up to 100 quads in one pass
+
+ private static int maxQuads = 100;
+ private static int maxIndices = maxQuads * 6;
+ private static int mTexID;
+
+ public static void init() {
+ shader = GlUtils.createProgram(vertexShader,
+ fragmentShader);
+ if (shader == 0) {
+ Log.e(TAG, "Could not create program.");
+ return;
+ }
+ hMatrix = GLES20.glGetUniformLocation(shader, "u_mvp");
+ hTexColor = GLES20.glGetUniformLocation(shader, "u_color");
+ hBgColor = GLES20.glGetUniformLocation(shader, "u_bgcolor");
+ hScale = GLES20.glGetUniformLocation(shader, "u_scale");
+
+ hVertexPosition0 = GLES20.glGetAttribLocation(shader, "a_pos0");
+ hVertexPosition1 = GLES20.glGetAttribLocation(shader, "a_pos1");
+ hVertexLength0 = GLES20.glGetAttribLocation(shader, "a_len0");
+ hVertexLength1 = GLES20.glGetAttribLocation(shader, "a_len1");
+ hVertexFlip = GLES20.glGetAttribLocation(shader, "a_flip");
+
+ int[] mVboIds = new int[2];
+ GLES20.glGenBuffers(2, mVboIds, 0);
+ mIndicesBufferID = mVboIds[0];
+ mVertexFlipID = mVboIds[1];
+
+ // 0, 1, 0, 1
+ byte[] flip = new byte[maxQuads * 4];
+ for (int i = 0; i < flip.length; i++)
+ flip[i] = (byte) (i % 2);
+
+ short j = 0;
+ //mNumIndices = ((points.length) >> 2) * 6;
+
+ short[] indices = new short[maxIndices];
+ for (int i = 0; i < maxIndices; i += 6, j += 4) {
+ indices[i + 0] = (short) (j + 0);
+ indices[i + 1] = (short) (j + 1);
+ indices[i + 2] = (short) (j + 2);
+
+ indices[i + 3] = (short) (j + 2);
+ indices[i + 4] = (short) (j + 1);
+ indices[i + 5] = (short) (j + 3);
+ }
+
+ ByteBuffer buf = ByteBuffer.allocateDirect(maxIndices * 2)
+ .order(ByteOrder.nativeOrder());
+
+ ShortBuffer sbuf = buf.asShortBuffer();
+ sbuf.put(indices);
+ sbuf.flip();
+ GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferID);
+ GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, indices.length * 2, sbuf,
+ GLES20.GL_STATIC_DRAW);
+ GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ buf.clear();
+ buf.put(flip);
+ buf.flip();
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexFlipID);
+ GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, flip.length, buf,
+ GLES20.GL_STATIC_DRAW);
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+
+ byte[] stipple = new byte[2];
+ stipple[0] = 8;
+ stipple[1] = 8;
+ //stipple[2] = 16;
+ //stipple[3] = 48;
+
+ mTexID = GlUtils.loadStippleTexture(stipple);
+
+ }
+
+ private final static int STRIDE = 12;
+ private final static int LEN_OFFSET = 8;
+
+ public static Layer draw(Layers layers, Layer curLayer,
+ MapPosition pos, float[] matrix, float div) {
+
+ GLState.blend(true);
+ GLState.useProgram(shader);
+
+ GLState.enableVertexArrays(-1, -1);
+
+ GLES20.glEnableVertexAttribArray(hVertexPosition0);
+ GLES20.glEnableVertexAttribArray(hVertexPosition1);
+ GLES20.glEnableVertexAttribArray(hVertexLength0);
+ GLES20.glEnableVertexAttribArray(hVertexLength1);
+ GLES20.glEnableVertexAttribArray(hVertexFlip);
+
+ GLES20.glUniformMatrix4fv(hMatrix, 1, false, matrix, 0);
+ GLES20.glUniform1f(hScale, pos.scale / div);
+
+ GLES20.glUniform4f(hTexColor, 1.0f, 1.0f, 1.0f, 1.0f);
+ //aa9988
+
+ GLES20.glUniform4f(hBgColor, 0x99 / 255f, 0x96 / 255f, 0x93 / 255f, 0.95f);
+
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexID);
+
+ GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,
+ mIndicesBufferID);
+
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexFlipID);
+ GLES20.glVertexAttribPointer(hVertexFlip, 1,
+ GLES20.GL_BYTE, false, 0, 0);
+
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, layers.vbo.id);
+
+ int offset = layers.texLineOffset;
+
+ Layer l = curLayer;
+ while (l != null && l.type == Layer.TEXLINE) {
+ LineTexLayer ll = (LineTexLayer) l;
+ //Line line = ll.line;
+
+ // first pass
+ int allIndices = (ll.evenQuads * 6);
+ for (int i = 0; i < allIndices; i += maxIndices) {
+ int numIndices = allIndices - i;
+ if (numIndices > maxIndices)
+ numIndices = maxIndices;
+
+ // i / 6 * (24 shorts per block * 2 short bytes)
+ int add = offset + i * 8;
+
+ GLES20.glVertexAttribPointer(hVertexPosition0,
+ 4, GLES20.GL_SHORT, false, STRIDE,
+ add + STRIDE);
+
+ GLES20.glVertexAttribPointer(hVertexLength0,
+ 2, GLES20.GL_SHORT, false, STRIDE,
+ add + STRIDE + LEN_OFFSET);
+
+ GLES20.glVertexAttribPointer(hVertexPosition1,
+ 4, GLES20.GL_SHORT, false, STRIDE,
+ add);
+
+ GLES20.glVertexAttribPointer(hVertexLength1,
+ 2, GLES20.GL_SHORT, false, STRIDE,
+ add + LEN_OFFSET);
+
+ GLES20.glDrawElements(GLES20.GL_TRIANGLES, numIndices,
+ GLES20.GL_UNSIGNED_SHORT, 0);
+ }
+
+ // second pass
+ allIndices = (ll.oddQuads * 6);
+ for (int i = 0; i < allIndices; i += maxIndices) {
+ int numIndices = allIndices - i;
+ if (numIndices > maxIndices)
+ numIndices = maxIndices;
+ // i / 6 * (24 shorts per block * 2 short bytes)
+ int add = offset + i * 8;
+
+ GLES20.glVertexAttribPointer(hVertexPosition0,
+ 4, GLES20.GL_SHORT, false, STRIDE,
+ add + 2 * STRIDE);
+
+ GLES20.glVertexAttribPointer(hVertexLength0,
+ 2, GLES20.GL_SHORT, false, STRIDE,
+ add + 2 * STRIDE + LEN_OFFSET);
+
+ GLES20.glVertexAttribPointer(hVertexPosition1,
+ 4, GLES20.GL_SHORT, false, STRIDE,
+ add + STRIDE);
+
+ GLES20.glVertexAttribPointer(hVertexLength1,
+ 2, GLES20.GL_SHORT, false, STRIDE,
+ add + STRIDE + LEN_OFFSET);
+
+ GLES20.glDrawElements(GLES20.GL_TRIANGLES, numIndices,
+ GLES20.GL_UNSIGNED_SHORT, 0);
+ }
+
+ l = l.next;
+ }
+
+ GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ GLES20.glDisableVertexAttribArray(hVertexPosition0);
+ GLES20.glDisableVertexAttribArray(hVertexPosition1);
+ GLES20.glDisableVertexAttribArray(hVertexLength0);
+ GLES20.glDisableVertexAttribArray(hVertexLength1);
+ GLES20.glDisableVertexAttribArray(hVertexFlip);
+ GlUtils.checkGlError("...");
+
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
+
+ return l;
+ }
+
+ final static String vertexShader = ""
+ + "precision mediump float;"
+ + "uniform mat4 u_mvp;"
+ + "uniform vec4 u_color;"
+ + "uniform float u_scale;"
+ + "attribute vec4 a_pos0;"
+ + "attribute vec4 a_pos1;"
+ + "attribute vec2 a_len0;"
+ + "attribute vec2 a_len1;"
+ + "attribute float a_flip;"
+ + "varying vec2 v_st;"
+ + "void main() {"
+ + " float div = (8.0 * 16.0) / max(ceil(log(u_scale)),1.0);"
+ + " if (a_flip == 0.0){"
+ + " vec2 dir = a_pos0.zw/16.0;"
+ + " gl_Position = u_mvp * vec4(a_pos0.xy + dir / u_scale, 0.0, 1.0);"
+ + " v_st = vec2(a_len0.x/div, 1.0);"
+ + " }else {"
+ + " vec2 dir = a_pos1.zw/16.0;"
+ + " gl_Position = u_mvp * vec4(a_pos1.xy - dir / u_scale, 0.0, 1.0);"
+ + " v_st = vec2(a_len1.x/div, -1.0);"
+ + " }"
+ + "}";
+
+ final static String fragmentShader = ""
+ + "#extension GL_OES_standard_derivatives : enable\n"
+ + "precision mediump float;"
+ + "uniform sampler2D tex;"
+ + " uniform vec4 u_color;"
+ + " uniform vec4 u_bgcolor;"
+ + "varying vec2 v_st;"
+ + "void main() {"
+ + " float len = texture2D(tex, v_st).a;"
+ + " float tex_w = abs(v_st.t);"
+ + " vec2 st_width = fwidth(v_st);"
+ + " float fuzz = max(st_width.s, st_width.t);"
+ + " float line_w = (1.0 - smoothstep(1.0 - fuzz, 1.0, tex_w));"
+ + " float stipple_w = (1.0 - smoothstep(0.7 - fuzz, 0.7, tex_w));"
+ + " float stipple_p = smoothstep(0.495, 0.505, len);"
+ + " gl_FragColor = line_w * mix(u_bgcolor, u_color, min(stipple_w, stipple_p));"
+
+ //+ " gl_FragColor = u_color * min(abs(1.0 - mod(v_len, 20.0)/10.0), (1.0 - abs(v_st.x)));"
+ + "}";
+
+}
diff --git a/src/org/oscim/renderer/MapTile.java b/src/org/oscim/renderer/MapTile.java
index bbb52f3d..49ee4e4f 100644
--- a/src/org/oscim/renderer/MapTile.java
+++ b/src/org/oscim/renderer/MapTile.java
@@ -37,15 +37,6 @@ public final class MapTile extends JobTile {
*/
public boolean isVisible;
- /**
- * VBO holds all vertex data to draw lines and polygons when
- * 'layers' are compiled. layout:
- * 16 bytes fill coordinates,
- * n bytes polygon vertices,
- * m bytes lines vertices
- */
- BufferObject vbo;
-
/**
* Pointer to access relatives in QuadTree
*/
diff --git a/src/org/oscim/renderer/TileManager.java b/src/org/oscim/renderer/TileManager.java
index 8e929b46..c8477c75 100644
--- a/src/org/oscim/renderer/TileManager.java
+++ b/src/org/oscim/renderer/TileManager.java
@@ -162,7 +162,7 @@ public class TileManager {
MapPosition mapPosition = mMapPosition;
float[] coords = mTileCoords;
- synchronized(mMapViewPosition){
+ synchronized (mMapViewPosition) {
changedPos = mMapViewPosition.getMapPosition(mapPosition);
mMapViewPosition.getMapViewProjection(coords);
}
@@ -390,17 +390,18 @@ public class TileManager {
return;
if (t.layers != null) {
+ // TODO move this to layers clear
+ if (t.layers.vbo != null) {
+ BufferObject.release(t.layers.vbo);
+ t.layers.vbo = null;
+ }
+
t.layers.clear();
t.layers = null;
}
TextItem.release(t.labels);
- if (t.vbo != null) {
- BufferObject.release(t.vbo);
- t.vbo = null;
- }
-
QuadTree.remove(t);
t.state = STATE_NONE;
@@ -522,19 +523,19 @@ public class TileManager {
tiles[i] = null;
}
}
-// if (locked) {
-// Log.d(TAG, "------------ "
-// + remove + " / " + r + " "
-// + mMapPosition.zoomLevel
-// + " ----------");
-// for (int i = 0; i < size; i++) {
-// MapTile t = tiles[i];
-// if (t == null)
-// continue;
-// Log.d(TAG, "limitCache: " + t + " " + t.distance);
-//
-// }
-// }
+ //if (locked) {
+ // Log.d(TAG, "------------ "
+ // + remove + " / " + r + " "
+ // + mMapPosition.zoomLevel
+ // + " ----------");
+ // for (int i = 0; i < size; i++) {
+ // MapTile t = tiles[i];
+ // if (t == null)
+ // continue;
+ // Log.d(TAG, "limitCache: " + t + " " + t.distance);
+ //
+ // }
+ //}
remove = (newTileCnt - MAX_TILES_IN_QUEUE) + 10;
//int r = remove;
for (int i = size - 1; i >= 0 && remove > 0; i--) {
@@ -572,11 +573,11 @@ public class TileManager {
return true;
}
- if (tile.vbo != null) {
- // BAD Things(tm) happend: tile is already loaded
- Log.d(TAG, "BUG: tile loaded before " + tile);
- return true;
- }
+ //if (tile.vbo != null) {
+ // // BAD Things(tm) happend: tile is already loaded
+ // Log.d(TAG, "BUG: tile loaded before " + tile);
+ // return true;
+ //}
tile.state = STATE_NEW_DATA;
mTilesForUpload++;
diff --git a/src/org/oscim/renderer/layer/ExtrusionLayer.java b/src/org/oscim/renderer/layer/ExtrusionLayer.java
index fd64c0c7..bb95f2f9 100644
--- a/src/org/oscim/renderer/layer/ExtrusionLayer.java
+++ b/src/org/oscim/renderer/layer/ExtrusionLayer.java
@@ -64,7 +64,7 @@ public class ExtrusionLayer extends Layer {
public ExtrusionLayer(int level) {
this.type = Layer.EXTRUSION;
- this.layer = level;
+ this.level = level;
mVertices = mCurVertices = VertexPool.get();
@@ -346,6 +346,7 @@ public class ExtrusionLayer extends Layer {
return convex;
}
+ @Override
public void compile(ShortBuffer sbuf) {
if (mNumVertices == 0 || compiled)
diff --git a/src/org/oscim/renderer/layer/Layer.java b/src/org/oscim/renderer/layer/Layer.java
index 1562bbb5..04e6c582 100644
--- a/src/org/oscim/renderer/layer/Layer.java
+++ b/src/org/oscim/renderer/layer/Layer.java
@@ -14,24 +14,28 @@
*/
package org.oscim.renderer.layer;
+import java.nio.ShortBuffer;
+
/**
* @authorHannes Janetzek
*/
public abstract class Layer {
public final static byte LINE = 0;
public final static byte POLYGON = 1;
- public final static byte WAYTEXT = 2;
- public final static byte POITEXT = 3;
- public final static byte SYMBOL = 4;
- public final static byte BITMAP = 5;
- public final static byte TEXLINE = 6;
+ public final static byte TEXLINE = 2;
+ public final static byte WAYTEXT = 3;
+ public final static byte POITEXT = 4;
+ public final static byte SYMBOL = 5;
+ public final static byte BITMAP = 6;
public final static byte EXTRUSION = 7;
public byte type = -1;
public Layer next;
- int layer;
+ // drawing order from bottom to top
+ int level;
+
// number of vertices for this layer
public int verticesCnt;
@@ -44,5 +48,6 @@ public abstract class Layer {
VertexPoolItem pool;
protected VertexPoolItem curItem;
+ abstract protected void compile(ShortBuffer sbuf);
abstract protected void clear();
}
diff --git a/src/org/oscim/renderer/layer/Layers.java b/src/org/oscim/renderer/layer/Layers.java
index f6124226..4d2c1010 100644
--- a/src/org/oscim/renderer/layer/Layers.java
+++ b/src/org/oscim/renderer/layer/Layers.java
@@ -16,22 +16,33 @@ package org.oscim.renderer.layer;
import java.nio.ShortBuffer;
+import org.oscim.renderer.BufferObject;
+
import android.util.Log;
-/**
- * @author Hannes Janetzek
- */
public class Layers {
- // mixed Polygon and Line layers
- public Layer layers;
+ private final static String TAG = Layers.class.getName();
+
+ // mixed Polygon- and LineLayer
+ public Layer baseLayers;
public Layer textureLayers;
public Layer extrusionLayers;
+ // VBO holds all vertex data to draw lines and polygons
+ // after are compilation.
+ // Layout:
+ // 16 bytes fill coordinates,
+ // n bytes polygon vertices,
+ // m bytes lines vertices
+ // ...
+ public BufferObject vbo;
+
// To not need to switch VertexAttribPointer positions all the time:
// 1. polygons are packed in VBO at offset 0
// 2. lines afterwards at lineOffset
// 3. other layers keep their byte offset in Layer.offset
public int lineOffset;
+ public int texLineOffset;
// time when layers became first rendered (in uptime)
// used for animations
@@ -39,93 +50,109 @@ public class Layers {
private Layer mCurLayer;
- // get or add the line- or polygon-layer for a level.
+ // get or add the Line- or PolygonLayer for a level.
public Layer getLayer(int level, byte type) {
- Layer l = layers;
- Layer ret = null;
+ Layer l = baseLayers;
+ Layer layer = null;
- if (mCurLayer != null && mCurLayer.layer == level) {
- ret = mCurLayer;
- } else if (l == null || l.layer > level) {
- // insert new layer at start
- l = null;
+ if (mCurLayer != null && mCurLayer.level == level) {
+ layer = mCurLayer;
} else {
- while (true) {
- if (l.layer == level) {
- // found layer
- ret = l;
- break;
- }
- if (l.next == null || l.next.layer > level) {
+ if (l == null || l.level > level) {
+ // insert new layer at start
+ l = null;
+ } else {
+ while (true) {
+ // found layer
+ if (l.level == level) {
+ layer = l;
+ break;
+ }
+
// insert new layer between current and next layer
- break;
+ if (l.next == null || l.next.level > level)
+ break;
+
+ l = l.next;
+ }
+ }
+
+ if (layer == null) {
+ // add a new Layer
+ if (type == Layer.LINE)
+ layer = new LineLayer(level);
+ else if (type == Layer.POLYGON)
+ layer = new PolygonLayer(level);
+ else if (type == Layer.TEXLINE)
+ layer = new LineTexLayer(level);
+ else
+ // TODO throw execption
+ return null;
+
+ if (l == null) {
+ // insert at start
+ layer.next = baseLayers;
+ baseLayers = layer;
+ } else {
+ layer.next = l.next;
+ l.next = layer;
}
- l = l.next;
}
}
- if (ret == null) {
- if (type == Layer.LINE)
- ret = new LineLayer(level);
- else if (type == Layer.POLYGON)
- ret = new PolygonLayer(level);
- else
- return null;
- if (l == null) {
- // insert at start
- ret.next = layers;
- layers = ret;
- } else {
- ret.next = l.next;
- l.next = ret;
- }
- } else if (ret.type != type) {
- Log.d("...", "wrong layer type " + ret.type + " " + type);
- // FIXME thorw exception
+ if (layer.type != type) {
+ // check if found layer matches requested type
+ Log.d(TAG, "BUG wrong layer " + layer.type + " " + type);
+ // TODO throw exception
return null;
}
- return ret;
+ mCurLayer = layer;
+
+ return layer;
}
- private static int LINE_VERTEX_SHORTS = 4;
- private static int POLY_VERTEX_SHORTS = 2;
- private static int TEXTURE_VERTEX_SHORTS = 6;
+ private final static int[] VERTEX_SHORT_CNT = {
+ 4, // LINE_VERTEX_SHORTS
+ 2, // POLY_VERTEX_SHORTS
+ 6, // TEXLINE_VERTEX_SHORTS
+ };
- //private static int EXTRUSION_VERTEX_SHORTS = 4;
+ private final static int TEXTURE_VERTEX_SHORTS = 6;
+
+ private final static int SHORT_BYTES = 2;
public int getSize() {
-
int size = 0;
- for (Layer l = layers; l != null; l = l.next) {
- if (l.type == Layer.LINE)
- size += l.verticesCnt * LINE_VERTEX_SHORTS;
- else
- size += l.verticesCnt * POLY_VERTEX_SHORTS;
- }
+ for (Layer l = baseLayers; l != null; l = l.next)
+ size += l.verticesCnt * VERTEX_SHORT_CNT[l.type];
for (Layer l = textureLayers; l != null; l = l.next)
size += l.verticesCnt * TEXTURE_VERTEX_SHORTS;
- //for (Layer l = extrusionLayers; l != null; l = l.next)
- // size += l.verticesCnt * EXTRUSION_VERTEX_SHORTS;
-
return size;
}
public void compile(ShortBuffer sbuf, boolean addFill) {
// offset from fill coordinates
int pos = 0;
- if (addFill)
+ int size = 0;
+
+ if (addFill){
pos = 4;
+ size = 8;
+ }
- // add polygons first, needed to get the offsets right...
- addLayerItems(sbuf, layers, Layer.POLYGON, pos);
+ size += addLayerItems(sbuf, baseLayers, Layer.POLYGON, pos);
- lineOffset = sbuf.position() * 2; // * short-bytes
- addLayerItems(sbuf, layers, Layer.LINE, 0);
+ lineOffset = size * SHORT_BYTES;
+ size += addLayerItems(sbuf, baseLayers, Layer.LINE, 0);
+
+
+ texLineOffset = size * SHORT_BYTES;
+ size += addLayerItems(sbuf, baseLayers, Layer.TEXLINE, 0);
for (Layer l = textureLayers; l != null; l = l.next) {
TextureLayer tl = (TextureLayer) l;
@@ -139,20 +166,33 @@ public class Layers {
// }
}
- // optimization for lines and polygon: collect all pool items and add back in one go
- private static void addLayerItems(ShortBuffer sbuf, Layer l, byte type, int pos) {
+ // optimization for Line- and PolygonLayer:
+ // collect all pool items and add back in one go
+ private static int addLayerItems(ShortBuffer sbuf, Layer l, byte type, int pos) {
VertexPoolItem last = null, items = null;
+ int size = 0;
+
+ // HACK, see LineTexLayer
+ boolean addOffset = (type == Layer.TEXLINE);
for (; l != null; l = l.next) {
if (l.type != type)
continue;
- for (VertexPoolItem it = l.pool; it != null; it = it.next) {
- if (it.next == null)
- sbuf.put(it.vertices, 0, it.used);
- else
- sbuf.put(it.vertices, 0, VertexPoolItem.SIZE);
+ if (addOffset){
+ sbuf.position(sbuf.position() + 6);
+ addOffset = false;
+ }
+ for (VertexPoolItem it = l.pool; it != null; it = it.next) {
+ if (it.next == null){
+ size += it.used;
+ sbuf.put(it.vertices, 0, it.used);
+ }
+ else{
+ size += VertexPoolItem.SIZE;
+ sbuf.put(it.vertices, 0, VertexPoolItem.SIZE);
+ }
last = it;
}
if (last == null)
@@ -169,11 +209,13 @@ public class Layers {
l.curItem = null;
}
VertexPool.release(items);
+
+ return size;
}
static void addPoolItems(Layer l, ShortBuffer sbuf) {
// offset of layer data in vbo
- l.offset = sbuf.position() * 2; // (* short-bytes)
+ l.offset = sbuf.position() * SHORT_BYTES;
for (VertexPoolItem it = l.pool; it != null; it = it.next) {
if (it.next == null)
@@ -190,7 +232,7 @@ public class Layers {
public void clear() {
// clear line and polygon layers directly
- Layer l = layers;
+ Layer l = baseLayers;
while (l != null) {
if (l.pool != null) {
VertexPool.release(l.pool);
@@ -207,8 +249,13 @@ public class Layers {
for (l = extrusionLayers; l != null; l = l.next) {
l.clear();
}
- layers = null;
+ baseLayers = null;
textureLayers = null;
extrusionLayers = null;
+
+ // if (vbo != null){
+ // BufferObject.release(vbo);
+ // vbo = null;
+ // }
}
}
diff --git a/src/org/oscim/renderer/layer/LineLayer.java b/src/org/oscim/renderer/layer/LineLayer.java
index bb82365c..d1443e3b 100644
--- a/src/org/oscim/renderer/layer/LineLayer.java
+++ b/src/org/oscim/renderer/layer/LineLayer.java
@@ -14,6 +14,8 @@
*/
package org.oscim.renderer.layer;
+import java.nio.ShortBuffer;
+
import org.oscim.core.Tile;
import org.oscim.renderer.GLRenderer;
import org.oscim.theme.renderinstruction.Line;
@@ -26,7 +28,6 @@ import android.graphics.Paint.Cap;
* @author Hannes Janetzek
*/
public final class LineLayer extends Layer {
-
private static final float COORD_SCALE = GLRenderer.COORD_MULTIPLIER;
// scale factor mapping extrusion vector to short values
public static final float DIR_SCALE = 2048;
@@ -42,7 +43,7 @@ public final class LineLayer extends Layer {
public boolean roundCap;
LineLayer(int layer) {
- this.layer = layer;
+ this.level = layer;
this.type = Layer.LINE;
}
@@ -312,11 +313,13 @@ public final class LineLayer extends Layer {
vx *= -1;
vy *= -1;
+ int end = pos + length;
+
for (;;) {
- if (ipos < pos + length) {
+ if (ipos < end) {
nextX = points[ipos++];
nextY = points[ipos++];
- } else if (closed && ipos < pos + length + 2) {
+ } else if (closed && ipos < end + 2) {
// add startpoint == endpoint
nextX = points[pos];
nextY = points[pos + 1];
@@ -543,4 +546,8 @@ public final class LineLayer extends Layer {
@Override
protected void clear() {
}
+
+ @Override
+ protected void compile(ShortBuffer sbuf) {
+ }
}
diff --git a/src/org/oscim/renderer/layer/LineTexLayer.java b/src/org/oscim/renderer/layer/LineTexLayer.java
new file mode 100644
index 00000000..443089fb
--- /dev/null
+++ b/src/org/oscim/renderer/layer/LineTexLayer.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2013 Hannes Janetzek
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.renderer.layer;
+
+import java.nio.ShortBuffer;
+
+import org.oscim.renderer.GLRenderer;
+import org.oscim.theme.renderinstruction.Line;
+import org.oscim.utils.FastMath;
+
+/**
+ * Layer for textured or stippled lines
+ */
+public final class LineTexLayer extends Layer {
+ // Interleave two segment quads in one block to be able to use
+ // vertices twice. pos0 and pos1 use the same vertex array where
+ // pos1 has an offset of one vertex. The vertex shader will use
+ // pos0 when the vertexId is even, pos1 when the Id is odd.
+ //
+ // As there is no gl_VertexId in gles 2.0 an additional 'flip'
+ // array is used. Depending on 'flip' extrusion is inverted.
+ //
+ // Indices and flip buffers can be static.
+ //
+ // First pass: using even vertex array positions
+ // (used vertices are in braces)
+ // vertex id 0 1 2 3 4 5 6 7
+ // pos0 x (0) 1 (2) 3 (4) 5 (6) 7 x
+ // pos1 x (0) 1 (2) 3 (4) 5 (6) 7 x
+ // flip 0 1 0 1 0 1 0 1
+ //
+ // Second pass: using odd vertex array positions
+ // vertex id 0 1 2 3 4 5 6 7
+ // pos0 x 0 (1) 2 (3) 4 (5) 6 (7) x
+ // pos1 x 0 (1) 2 (3) 4 (5) 6 (7) x
+ // flip 0 1 0 1 0 1 0 1
+ //
+ // Vertex layout:
+ // [2 short] position,
+ // [2 short] extrusion,
+ // [1 short] line length
+ // [1 short] unused
+ //
+ // indices, for two blocks:
+ // 0, 1, 2,
+ // 2, 1, 3,
+ // 4, 5, 6,
+ // 6, 5, 7,
+
+ private static final float COORD_SCALE = GLRenderer.COORD_MULTIPLIER;
+ // scale factor mapping extrusion vector to short values
+ public static final float DIR_SCALE = 255; //2048;
+
+ // lines referenced by this outline layer
+ public LineLayer outlines;
+ public Line line;
+ public float width;
+
+ public boolean roundCap;
+
+ public int evenQuads;
+ public int oddQuads;
+
+ private boolean evenSegment;
+
+ LineTexLayer(int layer) {
+ this.level = layer;
+ this.type = Layer.TEXLINE;
+ this.evenSegment = true;
+ }
+
+ public void addLine(float[] points, short[] index) {
+
+ if (pool == null) {
+ curItem = pool = VertexPool.get();
+ // need to make sure there is one unused
+ // vertex in front for interleaving.
+
+ // HACK add this offset when compiling
+ // otherwise one cant use the full
+ // VertexItem
+ //curItem.used = 6;
+
+ verticesCnt = 1;
+ }
+
+ VertexPoolItem si = curItem;
+
+ short v[] = si.vertices;
+ int opos = si.used;
+
+ boolean even = evenSegment;
+
+ // reset offset to last written position
+ if (!even)
+ opos -= 12;
+
+ int n;
+ int length = 0;
+
+ if (index == null) {
+ n = 1;
+ length = points.length;
+ } else {
+ n = index.length;
+ }
+
+ for (int i = 0, pos = 0; i < n; i++) {
+ if (index != null)
+ length = index[i];
+
+ // check end-marker in indices
+ if (length < 0)
+ break;
+
+ // need at least two points
+ if (length < 4) {
+ pos += length;
+ continue;
+ }
+
+ int ipos = pos;
+
+ float x = points[ipos++] * COORD_SCALE;
+ float y = points[ipos++] * COORD_SCALE;
+
+ // randomize a bit
+ float lineLength = FastMath.abs(x * y) % 20;
+
+ int end = pos + length;
+
+ for (; ipos < end;) {
+ float nx = points[ipos++] * COORD_SCALE;
+ float ny = points[ipos++] * COORD_SCALE;
+
+ // Calculate triangle corners for the given width
+ float vx = nx - x;
+ float vy = ny - y;
+
+ float a = (float) Math.sqrt(vx * vx + vy * vy);
+
+ // normal vector
+ vx /= a;
+ vy /= a;
+
+ // perpendicular to line segment
+ float ux = -vy;
+ float uy = vx;
+
+ short dx = (short) (ux * DIR_SCALE);
+ short dy = (short) (uy * DIR_SCALE);
+
+ if (opos == VertexPoolItem.SIZE) {
+ si = si.next = VertexPool.get();
+ v = si.vertices;
+ opos = 0;
+ }
+
+ v[opos + 0] = (short) x;
+ v[opos + 1] = (short) y;
+ v[opos + 2] = dx;
+ v[opos + 3] = dy;
+ v[opos + 4] = (short) lineLength;
+ v[opos + 5] = 0;
+
+ lineLength += a;
+ v[opos + 12] = (short) nx;
+ v[opos + 13] = (short) ny;
+ v[opos + 14] = dx;
+ v[opos + 15] = dy;
+ v[opos + 16] = (short) lineLength;
+ v[opos + 17] = 0;
+
+ x = nx;
+ y = ny;
+
+ if (even) {
+ // go to second segment
+ opos += 6;
+ even = false;
+
+ // vertex 0 and 2 were added
+ verticesCnt += 3;
+ evenQuads++;
+ } else {
+ // go to next block
+ even = true;
+ opos += 18;
+
+ // vertex 1 and 3 were added
+ verticesCnt += 1;
+ oddQuads++;
+ }
+ }
+
+ pos += length;
+ }
+
+ // advance offset to last written position
+ if (!even)
+ opos += 12;
+
+ si.used = opos;
+ curItem = si;
+
+ evenSegment = even;
+ }
+
+ @Override
+ protected void clear() {
+ }
+
+ @Override
+ protected void compile(ShortBuffer sbuf) {
+ }
+
+}
diff --git a/src/org/oscim/renderer/layer/PolygonLayer.java b/src/org/oscim/renderer/layer/PolygonLayer.java
index f371f527..77a0b0cc 100644
--- a/src/org/oscim/renderer/layer/PolygonLayer.java
+++ b/src/org/oscim/renderer/layer/PolygonLayer.java
@@ -14,6 +14,8 @@
*/
package org.oscim.renderer.layer;
+import java.nio.ShortBuffer;
+
import org.oscim.core.Tile;
import org.oscim.renderer.GLRenderer;
import org.oscim.theme.renderinstruction.Area;
@@ -24,7 +26,7 @@ public final class PolygonLayer extends Layer {
public Area area;
PolygonLayer(int layer) {
- this.layer = layer;
+ this.level = layer;
this.type = Layer.POLYGON;
curItem = VertexPool.get();
pool = curItem;
@@ -87,6 +89,10 @@ public final class PolygonLayer extends Layer {
curItem = si;
}
+ @Override
+ protected void compile(ShortBuffer sbuf) {
+ }
+
@Override
protected void clear() {
}
diff --git a/src/org/oscim/renderer/layer/TextureLayer.java b/src/org/oscim/renderer/layer/TextureLayer.java
index a5fc3aa2..3d4879dd 100644
--- a/src/org/oscim/renderer/layer/TextureLayer.java
+++ b/src/org/oscim/renderer/layer/TextureLayer.java
@@ -32,7 +32,8 @@ public abstract class TextureLayer extends Layer {
* @param sbuf
* buffer to add vertices
*/
- void compile(ShortBuffer sbuf) {
+ @Override
+ protected void compile(ShortBuffer sbuf) {
for (TextureObject to = textures; to != null; to = to.next)
TextureObject.uploadTexture(to);
diff --git a/src/org/oscim/renderer/layer/VertexPoolItem.java b/src/org/oscim/renderer/layer/VertexPoolItem.java
index ca3e23d9..570e96aa 100644
--- a/src/org/oscim/renderer/layer/VertexPoolItem.java
+++ b/src/org/oscim/renderer/layer/VertexPoolItem.java
@@ -22,7 +22,7 @@ public class VertexPoolItem {
// must be multiple of
// 4 (LineLayer/PolygonLayer),
- // 6 (TexLineLayer)
+ // 24 (TexLineLayer - one block, i.e. two segments)
// 24 (TextureLayer)
public static final int SIZE = 360;
}
diff --git a/src/org/oscim/renderer/overlays/BasicOverlay.java b/src/org/oscim/renderer/overlays/BasicOverlay.java
index bd328ac6..28fa5f82 100644
--- a/src/org/oscim/renderer/overlays/BasicOverlay.java
+++ b/src/org/oscim/renderer/overlays/BasicOverlay.java
@@ -20,6 +20,7 @@ import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.GLRenderer.Matrices;
import org.oscim.renderer.GLState;
import org.oscim.renderer.LineRenderer;
+import org.oscim.renderer.LineTexRenderer;
import org.oscim.renderer.PolygonRenderer;
import org.oscim.renderer.TextureRenderer;
import org.oscim.renderer.layer.Layer;
@@ -34,8 +35,6 @@ public abstract class BasicOverlay extends RenderOverlay {
public final Layers layers;
- public BufferObject vbo;
-
protected float[] mvp = new float[16];
public BasicOverlay(MapView mapView) {
@@ -51,17 +50,23 @@ public abstract class BasicOverlay extends RenderOverlay {
float div = FastMath.pow(mMapPosition.zoomLevel - pos.zoomLevel);
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo.id);
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, layers.vbo.id);
GLState.test(false, false);
- if (layers.layers != null) {
+ if (layers.baseLayers != null) {
setMatrix(pos, m, true);
- for (Layer l = layers.layers; l != null;) {
- if (l.type == Layer.POLYGON) {
- l = PolygonRenderer.draw(pos, l, m.mvp, true, false);
- } else {
- l = LineRenderer.draw(pos, l, m.mvp, div, 0, layers.lineOffset);
+ for (Layer l = layers.baseLayers; l != null;) {
+ switch (l.type) {
+ case Layer.POLYGON:
+ l = PolygonRenderer.draw(pos, l, m.mvp, true, false);
+ break;
+ case Layer.LINE:
+ l = LineRenderer.draw(layers, l, pos, m.mvp, div, 0);
+ break;
+ case Layer.TEXLINE:
+ l = LineTexRenderer.draw(layers, l, pos, m.mvp, div);
+ break;
}
}
}
@@ -81,21 +86,21 @@ public abstract class BasicOverlay extends RenderOverlay {
public void compile() {
int newSize = layers.getSize();
if (newSize == 0) {
- BufferObject.release(vbo);
- vbo = null;
+ BufferObject.release(layers.vbo);
+ layers.vbo = null;
isReady = false;
return;
}
- if (vbo == null) {
- vbo = BufferObject.get(0);
+ if (layers.vbo == null) {
+ layers.vbo = BufferObject.get(0);
- if (vbo == null)
+ if (layers.vbo == null)
return;
}
if (newSize > 0) {
- if (GLRenderer.uploadLayers(layers, vbo, newSize, true))
+ if (GLRenderer.uploadLayers(layers, newSize, true))
isReady = true;
}
}
diff --git a/src/org/oscim/renderer/overlays/TestLineOverlay.java b/src/org/oscim/renderer/overlays/TestLineOverlay.java
index 3041bfe0..aeddbf4c 100644
--- a/src/org/oscim/renderer/overlays/TestLineOverlay.java
+++ b/src/org/oscim/renderer/overlays/TestLineOverlay.java
@@ -40,85 +40,51 @@ public class TestLineOverlay extends RenderOverlay {
super(mapView);
}
- // Interleave two quads to be able to use vertices
- // twice. pos0 and pos1 use the same vertex array
- // where pos1 is off-setted by one vertex. The
- // vertex shader will use pos0 when the vertexId
- // is even, pos1 when the Id is odd.
+ // Interleave two segment quads in one block to be able to use
+ // vertices twice. pos0 and pos1 use the same vertex array where
+ // pos1 is off-setted by one vertex. The vertex shader will use
+ // pos0 when the vertexId is even, pos1 when the Id is odd.
//
- // As there is no gl_VertexId in gles 2.0 an
- // additional 'flip' array is used.
- // Depending on 'flip' extrusion is inverted.
+ // As there is no gl_VertexId in gles 2.0 an additional 'flip'
+ // array is used. Depending on 'flip' extrusion is inverted.
//
// Indices and flip buffers can be static.
//
// First pass: using even vertex array positions
// (used vertices are in braces)
- // vertex id 0, 1, 2, 3
- // pos0 - (0) 1 (2) 3 -
- // pos1 - (0) 1 (2) 3 -
- // flip 0 1 0 1
+ // vertex id 0 1 2 3 4 5 6 7
+ // pos0 - (0) 1 (2) 3 (4) 5 (6) 7 -
+ // pos1 - (0) 1 (2) 3 (4) 5 (6) 7 -
+ // flip 0 1 0 1 0 1 0 1
//
// Second pass: using odd vertex array positions
- // vertex id 0, 1, 2, 3
- // pos0 - 0 (1) 2 (3) -
- // pos1 - 0 (1) 2 (3) -
- // flip 0 1 0 1
+ // vertex id 0 1 2 3 4 5 6 7
+ // pos0 - 0 (1) 2 (3) 4 (5) 6 (7) -
+ // pos1 - 0 (1) 2 (3) 4 (5) 6 (7) -
+ // flip 0 1 0 1 0 1 0 1
//
// Vertex layout:
- // x/y pos[16][16], dir_x[8]|dir_y[8], start[4]|length[12]
- // - 'direction' precision 1/16, maximum line width is 2*16
- // - texture 'start' prescision 1
- // -> max tex width is 32
- // - segment 'length' prescision 1/4
- // -> max line length is 2^12/4=1024
- // - texture 'end' is 'length'-'start'
-
- // private final short[] box = {
- // // '-' start
- // 0, 0, 0, 0,
- // // 0.
- // -800, 0, 255, 0,
- // // 2.
- // 100, 0, 255, 0,
- // // 1.
- // 0, 0, 255, 1,
- // // 3.
- // 800, 0, 255, 1,
+ // [2 short] position,
+ // [2 short] extrusion,
+ // [1 short] line length
+ // [1 short] unused
//
- // -800, 200, 127, 0,
- // 0, 200, 127, 0,
- // 0, 200, 127, 1,
- // 800, 200, 127, 1,
- //
- // -800, 400, 255, 0,
- // 0, 400, 255, 0,
- // 0, 400, 255, 1,
- // 800, 400, 255, 1,
- //
- // // '-' end
- // 0, 0, 0, 0,
- // };
-
- private short[] indices = {
- 0, 1, 2,
- 2, 1, 3,
-
- 4, 5, 6,
- 6, 5, 7,
-
- 8, 9, 10,
- 10, 9, 11,
- };
-
- private byte[] flip;
+ // indices: (two indice blocks)
+ // 0, 1, 2,
+ // 2, 1, 3,
+ // 4, 5, 6,
+ // 6, 5, 7,
private static int testProgram;
private static int htestVertexPosition0;
private static int htestVertexPosition1;
+ private static int htestVertexLength0;
+ private static int htestVertexLength1;
private static int htestVertexFlip;
private static int htestMatrix;
- private static int htestColor;
+ private static int htestTexColor;
+ private static int htestBgColor;
+ private static int htestScale;
private boolean initialized = false;
@@ -126,38 +92,52 @@ public class TestLineOverlay extends RenderOverlay {
+ "precision mediump float;"
+ "uniform mat4 u_mvp;"
+ "uniform vec4 u_color;"
+ + "uniform float u_scale;"
+ "attribute vec4 a_pos0;"
+ "attribute vec4 a_pos1;"
+ + "attribute vec2 a_len0;"
+ + "attribute vec2 a_len1;"
+ "attribute float a_flip;"
- + "varying vec4 color;"
- + "const float ff = 256.0;"
- + "const float ffff = 65536.0;"
+ + "varying vec2 v_st;"
+ "void main() {"
+ + " float div = (8.0 * 16.0) / max(ceil(log(u_scale)),1.0);"
+ " if (a_flip == 0.0){"
- // extract 8 bit direction vector
+ " vec2 dir = a_pos0.zw/16.0;"
- + " gl_Position = u_mvp * vec4(a_pos0.xy + dir, 0.0, 1.0);"
- + " color = vec4(dir/255.0 + 0.5, 1.0,1.0);"
+ + " gl_Position = u_mvp * vec4(a_pos0.xy + dir / u_scale, 0.0, 1.0);"
+ + " v_st = vec2(a_len0.x/div, 1.0);"
+ " }else {"
+ " vec2 dir = a_pos1.zw/16.0;"
- + " gl_Position = u_mvp * vec4(a_pos1.xy - dir, 0.0, 1.0);"
- + " color = vec4(dir/255.0 + 0.5, 1.0,1.0);"
- + "}}";
+ + " gl_Position = u_mvp * vec4(a_pos1.xy - dir / u_scale, 0.0, 1.0);"
+ + " v_st = vec2(a_len1.x/div, -1.0);"
+ + " }"
+ + "}";
final static String testFragmentShader = ""
+ "precision mediump float;"
- + "varying vec4 color;"
+ + "uniform sampler2D tex;"
+ + " uniform vec4 u_color;"
+ + " uniform vec4 u_bgcolor;"
+ + "varying vec2 v_st;"
+ "void main() {"
- + " gl_FragColor = color;"
+ + " float len = texture2D(tex, v_st).a;"
+ + " float tex_w = abs(v_st.t);"
+ + " float line_w = (1.0 - smoothstep(0.7, 1.0, tex_w));"
+ + " float stipple_w = (1.0 - smoothstep(0.1, 0.6, tex_w));"
+ + " float stipple_p = smoothstep(0.495, 0.505, len);"
+ + " gl_FragColor = line_w * mix(u_bgcolor, u_color, min(stipple_w, stipple_p));"
+
+ //+ " gl_FragColor = u_color * min(abs(1.0 - mod(v_len, 20.0)/10.0), (1.0 - abs(v_st.x)));"
+ "}";
private int mIndicesBufferID;
private int mVertexBufferID;
private int mVertexFlipID;
- private int mNumVertices;
+ //private int mNumVertices;
private int mNumIndices;
+ private int mTexID;
+
@Override
public synchronized void update(MapPosition curPos, boolean positionChanged,
boolean tilesChanged) {
@@ -174,9 +154,14 @@ public class TestLineOverlay extends RenderOverlay {
return;
}
htestMatrix = GLES20.glGetUniformLocation(testProgram, "u_mvp");
- htestColor = GLES20.glGetUniformLocation(testProgram, "u_color");
+ htestTexColor = GLES20.glGetUniformLocation(testProgram, "u_color");
+ htestBgColor = GLES20.glGetUniformLocation(testProgram, "u_bgcolor");
+ htestScale = GLES20.glGetUniformLocation(testProgram, "u_scale");
+
htestVertexPosition0 = GLES20.glGetAttribLocation(testProgram, "a_pos0");
htestVertexPosition1 = GLES20.glGetAttribLocation(testProgram, "a_pos1");
+ htestVertexLength0 = GLES20.glGetAttribLocation(testProgram, "a_len0");
+ htestVertexLength1 = GLES20.glGetAttribLocation(testProgram, "a_len1");
htestVertexFlip = GLES20.glGetAttribLocation(testProgram, "a_flip");
int[] mVboIds = new int[3];
@@ -186,34 +171,37 @@ public class TestLineOverlay extends RenderOverlay {
mVertexFlipID = mVboIds[2];
float points[] = {
- 800, 0,
- 0, 0,
- //-400, 100,
- //-600, 200,
- //-800, 100,
+ -800, -800,
+ 800, -800,
+ 800, 800,
+ -800, 800,
+ -800, -800,
};
// float[] points = new float[12 * 2];
// for (int i = 0; i < 24; i += 2) {
- // points[i + 0] = (float) Math.sin(-i / 11f * Math.PI) * 400;
- // points[i + 1] = (float) Math.cos(-i / 11f * Math.PI) * 400;
+ // points[i + 0] = (float) Math.sin(-i / 11f * Math.PI) * 8*400;
+ // points[i + 1] = (float) Math.cos(-i / 11f * Math.PI) * 8*400;
// }
- mNumVertices = (points.length - 2) * 2;
+ boolean oddSegments = points.length % 4 == 0;
- short[] vertices = new short[(mNumVertices + 2) * 4];
+ int numVertices = points.length + (oddSegments ? 2 : 0);
- int opos = 4;
+ short[] vertices = new short[numVertices * 6];
+
+ int opos = 6;
float x = points[0];
float y = points[1];
- float scale = 127;
+ float scale = 255;
boolean even = true;
+ float len = 0;
- for (int i = 2; i < points.length;) {
- float nx = points[i++];
- float ny = points[i++];
+ for (int i = 2; i < points.length; i += 2) {
+ float nx = points[i + 0];
+ float ny = points[i + 1];
// Calculate triangle corners for the given width
float vx = nx - x;
@@ -225,7 +213,7 @@ public class TestLineOverlay extends RenderOverlay {
vx /= a;
vy /= a;
- // perpendicular
+ // perpendicular to line segment
float ux = -vy;
float uy = vx;
@@ -236,33 +224,41 @@ public class TestLineOverlay extends RenderOverlay {
vertices[opos + 1] = (short) y;
vertices[opos + 2] = dx;
vertices[opos + 3] = dy;
+ vertices[opos + 4] = (short) len;
+ vertices[opos + 5] = 0;
- vertices[opos + 8] = (short) nx;
- vertices[opos + 9] = (short) ny;
- vertices[opos + 10] = dx;
- vertices[opos + 11] = dy;
+ len += a;
+ vertices[opos + 12] = (short) nx;
+ vertices[opos + 13] = (short) ny;
+ vertices[opos + 14] = dx;
+ vertices[opos + 15] = dy;
+ vertices[opos + 16] = (short) len;
+ vertices[opos + 17] = 0;
x = nx;
y = ny;
if (even) {
- opos += 4;
+ // go to second segment
+ opos += 6;
even = false;
} else {
+ // go to next block
even = true;
- opos += 12;
+ opos += 18;
}
}
- flip = new byte[(points.length - 2)];
+ // 0, 1, 0, 1
+ byte[] flip = new byte[points.length];
for (int i = 0; i < flip.length; i++)
flip[i] = (byte) (i % 2);
short j = 0;
mNumIndices = ((points.length) >> 2) * 6;
- indices = new short[mNumIndices];
+ short[] indices = new short[mNumIndices];
for (int i = 0; i < mNumIndices; i += 6, j += 4) {
indices[i + 0] = (short) (j + 0);
indices[i + 1] = (short) (j + 1);
@@ -273,7 +269,7 @@ public class TestLineOverlay extends RenderOverlay {
indices[i + 5] = (short) (j + 3);
}
- ByteBuffer buf = ByteBuffer.allocateDirect(128 * 4)
+ ByteBuffer buf = ByteBuffer.allocateDirect(numVertices * 6 * 2)
.order(ByteOrder.nativeOrder());
ShortBuffer sbuf = buf.asShortBuffer();
@@ -285,7 +281,6 @@ public class TestLineOverlay extends RenderOverlay {
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
sbuf.clear();
- //sbuf.put(box);
sbuf.put(vertices);
sbuf.flip();
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexBufferID);
@@ -300,12 +295,23 @@ public class TestLineOverlay extends RenderOverlay {
GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+ byte[] stipple = new byte[2];
+ stipple[0] = 8;
+ stipple[1] = 8;
+ //stipple[2] = 16;
+ //stipple[3] = 48;
+
+ mTexID = GlUtils.loadStippleTexture(stipple);
+
mMapView.getMapViewPosition().getMapPosition(mMapPosition);
// tell GLRenderer to call 'render'
isReady = true;
}
+ private final static int STRIDE = 12;
+ private final static int LEN_OFFSET = 8;
+
@Override
public synchronized void render(MapPosition pos, Matrices m) {
@@ -318,42 +324,79 @@ public class TestLineOverlay extends RenderOverlay {
GLState.enableVertexArrays(-1, -1);
GLES20.glEnableVertexAttribArray(htestVertexPosition0);
GLES20.glEnableVertexAttribArray(htestVertexPosition1);
-
+ GlUtils.checkGlError("-4");
+ GLES20.glEnableVertexAttribArray(htestVertexLength0);
+ GlUtils.checkGlError("-3");
+ GLES20.glEnableVertexAttribArray(htestVertexLength1);
+ GlUtils.checkGlError("-2");
GLES20.glEnableVertexAttribArray(htestVertexFlip);
GLES20.glUniformMatrix4fv(htestMatrix, 1, false, m.mvp, 0);
+ float div = FastMath.pow(pos.zoomLevel - mMapPosition.zoomLevel);
+ GLES20.glUniform1f(htestScale, pos.scale / mMapPosition.scale * div);
- GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferID);
+ GLES20.glUniform4f(htestTexColor, 1.0f, 1.0f, 1.0f, 1.0f);
+ GLES20.glUniform4f(htestBgColor, 0.3f, 0.3f, 0.3f, 1.0f);
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexID);
+
+ GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,
+ mIndicesBufferID);
+ GlUtils.checkGlError("-1");
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexFlipID);
- GLES20.glVertexAttribPointer(htestVertexFlip, 1, GLES20.GL_BYTE, false, 0, 0);
-
+ GLES20.glVertexAttribPointer(htestVertexFlip, 1,
+ GLES20.GL_BYTE, false, 0, 0);
+ GlUtils.checkGlError("0");
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexBufferID);
+ GlUtils.checkGlError("1");
+ // first pass
GLES20.glVertexAttribPointer(htestVertexPosition0,
- 4, GLES20.GL_SHORT, false, 0, 8);
+ 4, GLES20.GL_SHORT, false, STRIDE, STRIDE);
+ GlUtils.checkGlError("2");
+
+ GLES20.glVertexAttribPointer(htestVertexLength0,
+ 2, GLES20.GL_SHORT, false, STRIDE, STRIDE + LEN_OFFSET);
+ GlUtils.checkGlError("3");
GLES20.glVertexAttribPointer(htestVertexPosition1,
- 4, GLES20.GL_SHORT, false, 0, 0);
+ 4, GLES20.GL_SHORT, false, STRIDE, 0);
+ GlUtils.checkGlError("4");
- GLES20.glUniform4f(htestColor, 0.5f, 0.5f, 1.0f, 1.0f);
- GLES20.glDrawElements(GLES20.GL_TRIANGLES, mNumIndices, GLES20.GL_UNSIGNED_SHORT, 0);
+ GLES20.glVertexAttribPointer(htestVertexLength1,
+ 2, GLES20.GL_SHORT, false, STRIDE, LEN_OFFSET);
+ GlUtils.checkGlError("5");
+ //GLES20.glUniform4f(htestColor, 0.5f, 0.5f, 1.0f, 1.0f);
+ GLES20.glDrawElements(GLES20.GL_TRIANGLES, mNumIndices,
+ GLES20.GL_UNSIGNED_SHORT, 0);
+
+ // second pass
GLES20.glVertexAttribPointer(htestVertexPosition0,
- 4, GLES20.GL_SHORT, false, 0, 16);
+ 4, GLES20.GL_SHORT, false, STRIDE, 2 * STRIDE);
+
+ GLES20.glVertexAttribPointer(htestVertexLength0,
+ 2, GLES20.GL_SHORT, false, STRIDE, 2 * STRIDE + LEN_OFFSET);
GLES20.glVertexAttribPointer(htestVertexPosition1,
- 4, GLES20.GL_SHORT, false, 0, 8);
+ 4, GLES20.GL_SHORT, false, STRIDE, STRIDE);
- GLES20.glUniform4f(htestColor, 0.5f, 1.0f, 0.5f, 1.0f);
- GLES20.glDrawElements(GLES20.GL_TRIANGLES, mNumIndices, GLES20.GL_UNSIGNED_SHORT, 0);
+ GLES20.glVertexAttribPointer(htestVertexLength1,
+ 2, GLES20.GL_SHORT, false, STRIDE, STRIDE + LEN_OFFSET);
+
+ GLES20.glDrawElements(GLES20.GL_TRIANGLES, mNumIndices,
+ GLES20.GL_UNSIGNED_SHORT, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
GLES20.glDisableVertexAttribArray(htestVertexPosition0);
GLES20.glDisableVertexAttribArray(htestVertexPosition1);
+ GLES20.glDisableVertexAttribArray(htestVertexLength0);
+ GLES20.glDisableVertexAttribArray(htestVertexLength1);
GLES20.glDisableVertexAttribArray(htestVertexFlip);
GlUtils.checkGlError("...");
+
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
@Override
diff --git a/src/org/oscim/renderer/overlays/TestOverlay.java b/src/org/oscim/renderer/overlays/TestOverlay.java
index 75199392..62ecbb9c 100644
--- a/src/org/oscim/renderer/overlays/TestOverlay.java
+++ b/src/org/oscim/renderer/overlays/TestOverlay.java
@@ -14,13 +14,10 @@
*/
package org.oscim.renderer.overlays;
-import java.io.IOException;
-
import org.oscim.core.MapPosition;
-import org.oscim.renderer.layer.SymbolItem;
-import org.oscim.renderer.layer.SymbolLayer;
+import org.oscim.renderer.layer.Layer;
+import org.oscim.renderer.layer.LineTexLayer;
import org.oscim.renderer.layer.TextItem;
-import org.oscim.theme.renderinstruction.BitmapUtils;
import org.oscim.view.MapView;
public class TestOverlay extends BasicOverlay {
@@ -34,12 +31,33 @@ public class TestOverlay extends BasicOverlay {
public TestOverlay(MapView mapView) {
super(mapView);
- // LineLayer ll = (LineLayer) layers.getLayer(1, Layer.LINE);
- // ll.line = new Line(Color.BLUE, 1.0f, Cap.BUTT);
- // ll.width = 2;
- // float[] points = { -100, -100, 100, -100, 100, 100, -100, 100, -100, -100 };
- // short[] index = { (short) points.length };
- // ll.addLine(points, index, false);
+ // draw a rectangle
+ //LineLayer ll = (LineLayer) layers.getLayer(1, Layer.LINE);
+ //ll.line = new Line(Color.BLUE, 1.0f, Cap.BUTT);
+ //ll.width = 2;
+ float[] points = {
+ -100, -100,
+ 100, -100,
+ 100, 100,
+ -100, 100,
+ -100, -100
+ };
+ //short[] index = { (short) points.length };
+ //ll.addLine(points, index, true);
+
+
+ LineTexLayer lt = (LineTexLayer) layers.getLayer(2, Layer.TEXLINE);
+ lt.addLine(points, null);
+
+ float[] points2 = {
+ -200, -200,
+ 200, -200,
+ 200, 200,
+ -200, 200,
+ -200, -200
+ };
+
+ lt.addLine(points2, null);
//
// PolygonLayer pl = (PolygonLayer) layers.getLayer(0, Layer.POLYGON);
@@ -54,33 +72,33 @@ public class TestOverlay extends BasicOverlay {
// short[] pindex = { (short) ppoints.length };
// pl.addPolygon(ppoints, pindex);
- SymbolLayer sl = new SymbolLayer();
- SymbolItem it = new SymbolItem();
-
- it.x = 0;
- it.y = 0;
- // billboard always faces camera
- it.billboard = true;
-
- try {
- it.bitmap = BitmapUtils.createBitmap("file:/sdcard/cheshire.png");
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- sl.addSymbol(it);
-
- SymbolItem it2 = new SymbolItem();
- it2.bitmap = it.bitmap;
- it2.x = 0;
- it2.y = 0;
- // billboard always faces camera
- it2.billboard = false;
-
- sl.addSymbol(it2);
- sl.fixed = false;
-
- layers.textureLayers = sl;
+ //SymbolLayer sl = new SymbolLayer();
+ //SymbolItem it = new SymbolItem();
+ //
+ //it.x = 0;
+ //it.y = 0;
+ //// billboard always faces camera
+ //it.billboard = true;
+ //
+ //try {
+ // it.bitmap = BitmapUtils.createBitmap("file:/sdcard/cheshire.png");
+ //} catch (IOException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ //}
+ //sl.addSymbol(it);
+ //
+ //SymbolItem it2 = new SymbolItem();
+ //it2.bitmap = it.bitmap;
+ //it2.x = 0;
+ //it2.y = 0;
+ //// billboard always faces camera
+ //it2.billboard = false;
+ //
+ //sl.addSymbol(it2);
+ //sl.fixed = false;
+ //
+ //layers.textureLayers = sl;
// TextLayer tl = new TextLayer();
// Text t = Text.createText(20, 2, Color.WHITE, Color.BLACK, false);
@@ -106,7 +124,7 @@ public class TestOverlay extends BasicOverlay {
updateMapPosition();
first = false;
- ((SymbolLayer) (layers.textureLayers)).prepare();
+ //((SymbolLayer) (layers.textureLayers)).prepare();
// pass layers to be uploaded and drawn to GL Thread
// afterwards never modify 'layers' outside of this function!
diff --git a/src/org/oscim/renderer/overlays/TextOverlay.java b/src/org/oscim/renderer/overlays/TextOverlay.java
index f9a1125e..57626af5 100644
--- a/src/org/oscim/renderer/overlays/TextOverlay.java
+++ b/src/org/oscim/renderer/overlays/TextOverlay.java
@@ -386,8 +386,8 @@ public class TextOverlay extends BasicOverlay {
layers.clear();
if (mDebugLayer != null) {
- layers.layers = mDebugLayer.layers;
- mDebugLayer.layers = null;
+ layers.baseLayers = mDebugLayer.baseLayers;
+ mDebugLayer.baseLayers = null;
}
// set new TextLayer to be uploaded and used
diff --git a/src/org/oscim/renderer/overlays/TextOverlayExp.java b/src/org/oscim/renderer/overlays/TextOverlayExp.java
index 9acfa117..14901a29 100644
--- a/src/org/oscim/renderer/overlays/TextOverlayExp.java
+++ b/src/org/oscim/renderer/overlays/TextOverlayExp.java
@@ -627,7 +627,7 @@ public class TextOverlayExp extends BasicOverlay {
layers.clear();
if (mDebugLayer != null) {
- layers.layers = mDebugLayer.layers;
+ layers.baseLayers = mDebugLayer.baseLayers;
mDebugLayer = null;
}
@@ -665,12 +665,12 @@ public class TextOverlayExp extends BasicOverlay {
return;
}
- if (vbo == null) {
- vbo = BufferObject.get(0);
+ if (layers.vbo == null) {
+ layers.vbo = BufferObject.get(0);
}
if (newSize > 0) {
- if (GLRenderer.uploadLayers(layers, vbo, newSize, true))
+ if (GLRenderer.uploadLayers(layers, newSize, true))
isReady = true;
}
}
@@ -679,19 +679,19 @@ public class TextOverlayExp extends BasicOverlay {
public synchronized void render(MapPosition pos, Matrices m) {
float div = FastMath.pow(mMapPosition.zoomLevel - pos.zoomLevel);
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo.id);
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, layers.vbo.id);
GLState.test(false, false);
- if (layers.layers != null) {
+ if (layers.baseLayers != null) {
setMatrix(pos, m, true);
//Matrix.multiplyMM(m.mvp, 0, m.proj, 0, m.mvp,0);
- for (Layer l = layers.layers; l != null;) {
+ for (Layer l = layers.baseLayers; l != null;) {
if (l.type == Layer.POLYGON) {
l = PolygonRenderer.draw(pos, l, m.mvp, true, false);
} else {
float scale = pos.scale * div;
- l = LineRenderer.draw(pos, l, m.mvp, scale, 0, layers.lineOffset);
+ l = LineRenderer.draw(layers, l, pos, m.mvp, scale, 0);
}
}
}
diff --git a/src/org/oscim/theme/renderinstruction/Line.java b/src/org/oscim/theme/renderinstruction/Line.java
index a89f1f96..8b989578 100644
--- a/src/org/oscim/theme/renderinstruction/Line.java
+++ b/src/org/oscim/theme/renderinstruction/Line.java
@@ -229,35 +229,13 @@ public final class Line extends RenderInstruction {
this.fade = fade;
this.stipple = stipple;
this.min = min;
+
+ if (stipple != 0){
+ System.out.println("a");
+ }
}
- /**
- * @param line
- * ...
- * @param style
- * ...
- * @param src
- * ...
- * @param stroke
- * ...
- * @param strokeWidth
- * ...
- * @param stipple
- * ...
- * @param strokeLinecap
- * ...
- * @param level
- * ...
- * @param fixed
- * ...
- * @param fade
- * ...
- * @param blur
- * ...
- * @param isOutline
- * ...
- * @param min ...
- */
+
private Line(Line line, String style, String src, int stroke, float strokeWidth,
int stipple, Cap strokeLinecap, int level, boolean fixed,
int fade, float blur, boolean isOutline, float min) {
diff --git a/src/org/oscim/utils/FastMath.java b/src/org/oscim/utils/FastMath.java
index e5bb1bd6..a20a3c2a 100644
--- a/src/org/oscim/utils/FastMath.java
+++ b/src/org/oscim/utils/FastMath.java
@@ -54,6 +54,13 @@ public class FastMath {
return (pow > 0 ? (1 << pow) : (1.0f / (1 << -pow)));
}
+ public static int clamp(int value, int max, int min){
+ return (value < min ? min : (value > max ? max : value));
+ }
+
+ public static byte clampToByte(int value){
+ return (byte)(value < 0 ? 0 : (value > 255 ? 255 : value));
+ }
public static float abs(float value){
return value < 0 ? -value : value;
diff --git a/src/org/oscim/utils/GlUtils.java b/src/org/oscim/utils/GlUtils.java
index b7e1971b..466f5a0f 100644
--- a/src/org/oscim/utils/GlUtils.java
+++ b/src/org/oscim/utils/GlUtils.java
@@ -30,10 +30,25 @@ import android.util.Log;
public class GlUtils {
private static String TAG = "GlUtils";
+ public static void setTextureParameter(int min_filter, int mag_filter, int wrap_s, int wrap_t) {
+ GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+ GLES20.GL_TEXTURE_MIN_FILTER,
+ min_filter);
+ GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+ GLES20.GL_TEXTURE_MAG_FILTER,
+ mag_filter);
+ GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+ GLES20.GL_TEXTURE_WRAP_S,
+ wrap_s); // Set U Wrapping
+ GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+ GLES20.GL_TEXTURE_WRAP_T,
+ wrap_t); // Set V Wrapping
+ }
+
/**
* @param bitmap
* ...
- * @return gl identifier
+ * @return textureId
*/
public static int loadTextures(Bitmap bitmap) {
@@ -44,21 +59,8 @@ public class GlUtils {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER,
- GLES20.GL_LINEAR);
-
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER,
- GLES20.GL_LINEAR);
-
- GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S,
- GLES20.GL_CLAMP_TO_EDGE);
-
- GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T,
- GLES20.GL_CLAMP_TO_EDGE);
+ setTextureParameter(GLES20.GL_LINEAR, GLES20.GL_LINEAR,
+ GLES20.GL_CLAMP_TO_EDGE, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
@@ -66,24 +68,13 @@ public class GlUtils {
}
public static int loadTexture(byte[] pixel, int width, int height, int format,
- int wrap_s, int wrap_t) {
+ int min_filter, int mag_filter, int wrap_s, int wrap_t) {
int[] textureIds = new int[1];
GLES20.glGenTextures(1, textureIds, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER,
- GLES20.GL_NEAREST);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER,
- GLES20.GL_NEAREST);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S,
- wrap_s); // Set U Wrapping
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T,
- wrap_t); // Set V Wrapping
+ setTextureParameter(min_filter, mag_filter, wrap_s, wrap_t);
ByteBuffer buf = ByteBuffer.allocateDirect(width * height).order(ByteOrder.nativeOrder());
buf.put(pixel);
@@ -96,6 +87,37 @@ public class GlUtils {
return textureIds[0];
}
+ public static int loadStippleTexture(byte[] stipple) {
+ int sum = 0;
+ for (byte flip : stipple)
+ sum += flip;
+
+ byte[] pixel = new byte[sum];
+
+ boolean on = true;
+ int pos = 0;
+ for (byte flip : stipple) {
+ float max = flip;
+
+ for (int s = 0; s < flip; s++) {
+ float color = Math.abs(s / (max - 1) - 0.5f);
+ if (on)
+ color = 255 * (1 - color);
+ else
+ color = 255 * color;
+
+ pixel[pos + s] = FastMath.clampToByte((int) color);
+ }
+ on = !on;
+ pos += flip;
+ }
+
+ return loadTexture(pixel, sum, 1, GLES20.GL_ALPHA,
+ GLES20.GL_LINEAR, GLES20.GL_LINEAR,
+ //GLES20.GL_NEAREST, GLES20.GL_NEAREST,
+ GLES20.GL_REPEAT, GLES20.GL_REPEAT);
+ }
+
/**
* @param shaderType
* shader type