add HairlineLayer

This commit is contained in:
Hannes Janetzek 2014-09-10 20:20:37 +02:00
parent f390a903dc
commit 3cd2f9ea47
7 changed files with 353 additions and 9 deletions

View File

@ -0,0 +1,115 @@
package org.oscim.test;
import org.oscim.backend.canvas.Color;
import org.oscim.backend.canvas.Paint.Cap;
import org.oscim.core.GeometryBuffer;
import org.oscim.gdx.GdxMap;
import org.oscim.gdx.GdxMapApp;
import org.oscim.layers.GenericLayer;
import org.oscim.renderer.ElementRenderer;
import org.oscim.renderer.GLViewport;
import org.oscim.renderer.MapRenderer;
import org.oscim.renderer.elements.HairLineLayer;
import org.oscim.renderer.elements.LineLayer;
import org.oscim.renderer.elements.PolygonLayer;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.LineStyle.LineBuilder;
public class HairLineTest extends GdxMap {
static GeometryBuffer createLine(float r) {
GeometryBuffer in = new GeometryBuffer(100, 2);
for (int j = 0; j <= 12; j += 3) {
in.startLine();
for (int i = 0; i <= 120; i++) {
double rad = Math.toRadians(i * 3);
in.addPoint((float) (Math.cos(rad) * (r + j)), (float) (Math.sin(rad) * (r + j)));
}
}
return in;
}
static class Renderer extends ElementRenderer {
boolean init;
LineBuilder l = new LineStyle.LineBuilder()
.color(Color.WHITE)
.width(1.5f)
.cap(Cap.ROUND);
HairLineLayer ll = layers.addHairLineLayer(1, l.build());
//LineLayer ll = layers.addLineLayer(1, new LineStyle(Color.fade(Color.CYAN, 0.6f), 2.5f));
LineStyle style = new LineStyle(Color.fade(Color.MAGENTA, 0.6f), 2.5f);
HairLineLayer l1 = layers.addHairLineLayer(2, style);
//style = new LineStyle(Color.fade(Color.LTGRAY, 0.8f), 1.5f);
LineLayer l2 = layers.addLineLayer(3, style);
PolygonLayer pl = layers.addPolygonLayer(4, new AreaStyle.AreaBuilder()
.color(Color.BLUE)
//.outline(Color.CYAN, 1)
.build());
@Override
protected boolean setup() {
//ll.roundCap = true;
return super.setup();
}
@Override
protected void update(GLViewport v) {
if (!init) {
mMapPosition.copy(v.pos);
init = true;
GeometryBuffer g;
for (int i = 105; i < 160; i += 30) {
g = createLine(i);
ll.addLine(g);
//g.translate(10, 10);
//l1.addLine(g);
// int o = 0;
// for (int k = 0; k < g.index.length && g.index[k] >= 0; k++) {
//
// for (int j = 0; j < g.index[k];)
// ll.addPoint(g.points[o + j++], g.points[o + j++]);
//
// o += g.index[k];
// }
}
g = new GeometryBuffer(4, 2);
g.clear();
g.startPolygon();
g.addPoint(-100, -100);
g.addPoint(100, -100);
g.addPoint(100, 100);
g.addPoint(-100, 100);
g.translate(100, 100);
l2.addLine(g);
pl.addPolygon(g);
compile();
}
}
}
@Override
protected void createLayers() {
MapRenderer.setBackgroundColor(Color.BLACK);
mMap.layers().add(new GenericLayer(mMap, new Renderer()));
}
public static void main(String[] args) {
GdxMapApp.init();
GdxMapApp.run(new HairLineTest(), null, 400);
}
}

View File

@ -0,0 +1,39 @@
// mali 400's fp varying has only mediump...
// youilabs.com/blog/mobile-gpu-floating-point-accuracy-variances/
// community.arm.com/groups/arm-mali-graphics/blog/2011/09/06/
// at-home-on-the-range--why-floating-point-formats-matter-in-graphics
#ifdef GLES
precision highp float;
#endif
uniform mat4 u_mvp;
uniform vec2 u_screen;
attribute vec2 a_pos;
varying vec4 v_pos;
varying vec2 s_pos;
void
main(){
v_pos = u_mvp * vec4(a_pos, 0.0, 1.0);
s_pos = v_pos.xy / v_pos.w;
gl_Position = v_pos;
}
$$
#ifdef GLES
precision highp float;
#endif
uniform vec4 u_color;
uniform float u_width;
uniform vec2 u_screen;
varying vec4 v_pos;
varying vec2 s_pos;
void
main(){
vec2 pos = (v_pos.xy) / v_pos.w * u_screen;
float l = length(gl_FragCoord.xy - u_screen - pos.xy);
float z = clamp(0.6, 1.0, 1.2 - (v_pos.z/ v_pos.w));
gl_FragColor = u_color * (smoothstep(1.0, 0.0, l / u_width) * z);
}

View File

@ -4,6 +4,7 @@ import static org.oscim.layers.tile.MapTile.PROXY_GRAMPA;
import static org.oscim.layers.tile.MapTile.PROXY_PARENT;
import static org.oscim.layers.tile.MapTile.State.READY;
import static org.oscim.renderer.elements.RenderElement.BITMAP;
import static org.oscim.renderer.elements.RenderElement.HAIRLINE;
import static org.oscim.renderer.elements.RenderElement.LINE;
import static org.oscim.renderer.elements.RenderElement.MESH;
import static org.oscim.renderer.elements.RenderElement.POLYGON;
@ -18,6 +19,7 @@ import org.oscim.renderer.GLViewport;
import org.oscim.renderer.MapRenderer;
import org.oscim.renderer.elements.BitmapLayer;
import org.oscim.renderer.elements.ElementLayers;
import org.oscim.renderer.elements.HairLineLayer;
import org.oscim.renderer.elements.LineLayer;
import org.oscim.renderer.elements.LineTexLayer;
import org.oscim.renderer.elements.MeshLayer;
@ -71,6 +73,7 @@ public class VectorTileRenderer extends TileRenderer {
mClipMode = PolygonLayer.CLIP_DEPTH;
drawProxies = true;
break;
}
}
@ -191,7 +194,13 @@ public class VectorTileRenderer extends TileRenderer {
l = MeshLayer.Renderer.draw(l, v);
continue;
}
if (l.type == HAIRLINE) {
l = HairLineLayer.Renderer.draw(l, v);
continue;
}
/* just in case */
log.error("unknown layer {}", l.type);
l = l.next;
}
@ -205,6 +214,7 @@ public class VectorTileRenderer extends TileRenderer {
l = BitmapLayer.Renderer.draw(l, v, 1, mLayerAlpha);
continue;
}
log.error("unknown layer {}", l.type);
l = l.next;
}

View File

@ -32,6 +32,7 @@ import org.oscim.core.MapPosition;
import org.oscim.core.Tile;
import org.oscim.renderer.elements.BitmapLayer;
import org.oscim.renderer.elements.ElementLayers;
import org.oscim.renderer.elements.HairLineLayer;
import org.oscim.renderer.elements.LineLayer;
import org.oscim.renderer.elements.LineTexLayer;
import org.oscim.renderer.elements.MeshLayer;
@ -114,6 +115,11 @@ public abstract class ElementRenderer extends LayerRenderer {
l = MeshLayer.Renderer.draw(l, v);
continue;
}
if (l.type == RenderElement.HAIRLINE) {
l = HairLineLayer.Renderer.draw(l, v);
continue;
}
log.debug("invalid layer {}", l.type);
break;
}

View File

@ -16,6 +16,7 @@
*/
package org.oscim.renderer.elements;
import static org.oscim.renderer.elements.RenderElement.HAIRLINE;
import static org.oscim.renderer.elements.RenderElement.LINE;
import static org.oscim.renderer.elements.RenderElement.MESH;
import static org.oscim.renderer.elements.RenderElement.POLYGON;
@ -47,6 +48,7 @@ public class ElementLayers extends TileData {
2, // POLY_VERTEX
2, // MESH_VERTEX
4, // EXTRUSION_VERTEX
2, // HAIRLINE_VERTEX
};
private final static int TEXTURE_VERTEX_SHORTS = 6;
@ -112,6 +114,15 @@ public class ElementLayers extends TileData {
return l;
}
public HairLineLayer addHairLineLayer(int level, LineStyle style) {
HairLineLayer ll = getHairLineLayer(level);
if (ll == null)
return null;
ll.line = style;
return ll;
}
/**
* Get or add the LineLayer for a level. Levels are ordered from
* bottom (0) to top
@ -144,6 +155,14 @@ public class ElementLayers extends TileData {
return (LineTexLayer) getLayer(level, TEXLINE);
}
/**
* Get or add the TexLineLayer for a level. Levels are ordered from
* bottom (0) to top
*/
public HairLineLayer getHairLineLayer(int level) {
return (HairLineLayer) getLayer(level, HAIRLINE);
}
public TextLayer addTextLayer(TextLayer textLayer) {
textLayer.next = textureLayers;
textureLayers = textLayer;
@ -223,6 +242,8 @@ public class ElementLayers extends TileData {
layer = new LineTexLayer(level);
else if (type == MESH)
layer = new MeshLayer(level);
else if (type == HAIRLINE)
layer = new HairLineLayer(level);
if (layer == null)
throw new IllegalArgumentException();
@ -293,7 +314,7 @@ public class ElementLayers extends TileData {
//offset[TEXLINE] = size * SHORT_BYTES;
for (RenderElement l = baseLayers; l != null; l = l.next) {
if (l.type == TEXLINE || l.type == MESH) {
if (l.type == TEXLINE || l.type == MESH || l.type == HAIRLINE) {
l.compile(sbuf);
}
}
@ -340,8 +361,8 @@ public class ElementLayers extends TileData {
TextureLayer.Renderer.init();
BitmapLayer.Renderer.init();
MeshLayer.Renderer.init();
HairLineLayer.Renderer.init();
TextureItem.init(gl);
}
}

View File

@ -0,0 +1,152 @@
package org.oscim.renderer.elements;
import static org.oscim.backend.GL20.GL_ELEMENT_ARRAY_BUFFER;
import static org.oscim.backend.GL20.GL_LINES;
import static org.oscim.backend.GL20.GL_SHORT;
import static org.oscim.backend.GL20.GL_UNSIGNED_SHORT;
import static org.oscim.renderer.MapRenderer.COORD_SCALE;
import org.oscim.core.GeometryBuffer;
import org.oscim.renderer.GLShader;
import org.oscim.renderer.GLState;
import org.oscim.renderer.GLUtils;
import org.oscim.renderer.GLViewport;
import org.oscim.theme.styles.LineStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HairLineLayer extends IndexedRenderElement {
static final Logger log = LoggerFactory.getLogger(HairLineLayer.class);
public LineStyle line;
public HairLineLayer(int level) {
super(RenderElement.HAIRLINE);
this.level = level;
}
public void addLine(GeometryBuffer geom) {
short id = (short) numVertices;
float pts[] = geom.points;
boolean poly = geom.isPoly();
int inPos = 0;
for (int i = 0, n = geom.index.length; i < n; i++) {
int len = geom.index[i];
if (len < 0)
break;
if (len < 4 || (poly && len < 6)) {
inPos += len;
continue;
}
int end = inPos + len;
vertexItems.add((short) (pts[inPos++] * COORD_SCALE),
(short) (pts[inPos++] * COORD_SCALE));
short first = id;
indiceItems.add(id++);
numIndices++;
while (inPos < end) {
vertexItems.add((short) (pts[inPos++] * COORD_SCALE),
(short) (pts[inPos++] * COORD_SCALE));
indiceItems.add(id);
numIndices++;
if (inPos == end) {
if (poly) {
indiceItems.add(id);
numIndices++;
indiceItems.add(first);
numIndices++;
}
id++;
break;
}
indiceItems.add(id++);
numIndices++;
}
}
numVertices = id;
}
public static class Renderer {
static Shader shader;
static boolean init() {
shader = new Shader("hairline");
return true;
}
public static class Shader extends GLShader {
int uMVP, uColor, uWidth, uScreen, aPos;
Shader(String shaderFile) {
if (!create(shaderFile))
return;
uMVP = getUniform("u_mvp");
uColor = getUniform("u_color");
uWidth = getUniform("u_width");
uScreen = getUniform("u_screen");
aPos = getAttrib("a_pos");
}
public void set(GLViewport v) {
useProgram();
GLState.enableVertexArrays(aPos, -1);
v.mvp.setAsUniform(uMVP);
GL.glUniform2f(uScreen, v.getWidth() / 2, v.getHeight() / 2);
GL.glLineWidth(2);
}
}
public static RenderElement draw(RenderElement l, GLViewport v) {
GLState.blend(true);
Shader s = shader;
s.useProgram();
GLState.enableVertexArrays(s.aPos, -1);
v.mvp.setAsUniform(s.uMVP);
GL.glUniform2f(s.uScreen, v.getWidth() / 2, v.getHeight() / 2);
GL.glLineWidth(2);
for (; l != null && l.type == HAIRLINE; l = l.next) {
HairLineLayer ll = (HairLineLayer) l;
if (ll.indicesVbo == null)
continue;
ll.indicesVbo.bind();
GLUtils.setColor(s.uColor, ll.line.color, 1);
GL.glVertexAttribPointer(s.aPos, 2, GL_SHORT,
false, 0, ll.offset);
GL.glDrawElements(GL_LINES, ll.numIndices,
GL_UNSIGNED_SHORT, 0);
}
GL.glLineWidth(1);
GL.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
return l;
}
}
}

View File

@ -24,13 +24,14 @@ import org.oscim.utils.pool.Inlist;
public abstract class RenderElement extends Inlist<RenderElement> {
protected static GL20 GL;
public final static int LINE = 0;
public final static int TEXLINE = 1;
public final static int POLYGON = 2;
public final static int MESH = 3;
public final static int EXTRUSION = 4;
public final static int SYMBOL = 5;
public final static int BITMAP = 6;
public static final int LINE = 0;
public static final int TEXLINE = 1;
public static final int POLYGON = 2;
public static final int MESH = 3;
public static final int EXTRUSION = 4;
public static final int HAIRLINE = 5;
public static final int SYMBOL = 6;
public static final int BITMAP = 7;
public final int type;