/* * Copyright 2013 Hannes Janetzek * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see . */ package org.oscim.renderer.layer; import java.nio.ShortBuffer; import org.oscim.renderer.GLRenderer; import org.oscim.theme.renderinstruction.Line; /** * 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) { } }