- 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

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