vtm/src/org/oscim/renderer/layer/LineTexLayer.java
2013-10-09 01:55:54 +02:00

229 lines
5.1 KiB
Java

/*
* 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;
/**
* 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 = 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 = (x * x + y * y) % 80;
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) {
}
}