- add initial version of line stipple renderer

- 'vbo' moved to 'Layers'
This commit is contained in:
Hannes Janetzek 2013-02-22 05:30:24 +01:00
parent a0083ae484
commit 7cf4ca27f3
23 changed files with 1148 additions and 449 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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);"

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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)));"
+ "}";
}

View File

@ -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
*/

View File

@ -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++;

View File

@ -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)

View File

@ -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();
}

View File

@ -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;
// }
}
}

View File

@ -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) {
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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) {
}
}

View File

@ -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() {
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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!

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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) {

View File

@ -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;

View File

@ -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