move renderer.layer to renderer.sublayers and renderer.overlays to renderer.layers
This commit is contained in:
151
src/org/oscim/renderer/sublayers/BitmapLayer.java
Normal file
151
src/org/oscim/renderer/sublayers/BitmapLayer.java
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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.sublayers;
|
||||
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import org.oscim.renderer.GLRenderer;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
/**
|
||||
* Renderer for a single bitmap, width and height must be power of 2.
|
||||
*/
|
||||
public class BitmapLayer extends TextureLayer {
|
||||
// private final static String TAG = BitmapLayer.class.getName();
|
||||
private Bitmap mBitmap;
|
||||
private final boolean mReuseBitmap;
|
||||
private final short[] mVertices;
|
||||
/**
|
||||
* @param reuseBitmap false if the Bitmap should be recycled after
|
||||
* it is compiled to texture.
|
||||
* */
|
||||
public BitmapLayer(boolean reuseBitmap) {
|
||||
type = Layer.BITMAP;
|
||||
mReuseBitmap = reuseBitmap;
|
||||
mVertices = new short[24];
|
||||
|
||||
textures = new TextureItem(-1);
|
||||
|
||||
// used for size calculation of Layers buffer.
|
||||
verticesCnt = 4;
|
||||
}
|
||||
|
||||
public void setBitmap(Bitmap bitmap, int w, int h) {
|
||||
mWidth = w;
|
||||
mHeight = h;
|
||||
|
||||
mBitmap = bitmap;
|
||||
|
||||
TextureItem ti = this.textures;
|
||||
ti.ownBitmap = true;
|
||||
ti.width = mBitmap.getWidth();
|
||||
ti.height = mBitmap.getHeight();
|
||||
ti.bitmap = mBitmap;
|
||||
ti.vertices = TextureRenderer.INDICES_PER_SPRITE;
|
||||
}
|
||||
|
||||
private int mWidth, mHeight;
|
||||
|
||||
/**
|
||||
* Set target dimension to renderthe bitmap */
|
||||
public void setSize(int w, int h){
|
||||
mWidth = w;
|
||||
mHeight = h;
|
||||
}
|
||||
|
||||
private void setVertices(ShortBuffer sbuf){
|
||||
short[] buf = mVertices;
|
||||
short w = (short) (mWidth * GLRenderer.COORD_SCALE);
|
||||
short h = (short) (mHeight* GLRenderer.COORD_SCALE);
|
||||
|
||||
short t = 1;
|
||||
|
||||
int pos = 0;
|
||||
// top-left
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = 0;
|
||||
// bot-left
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = h;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = t;
|
||||
// top-right
|
||||
buf[pos++] = w;
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = t;
|
||||
buf[pos++] = 0;
|
||||
// bot-right
|
||||
buf[pos++] = w;
|
||||
buf[pos++] = h;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = t;
|
||||
buf[pos++] = t;
|
||||
|
||||
this.offset = sbuf.position() * 2; // bytes
|
||||
sbuf.put(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepare() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void compile(ShortBuffer sbuf) {
|
||||
|
||||
if (mBitmap == null)
|
||||
return;
|
||||
|
||||
setVertices(sbuf);
|
||||
|
||||
//for (TextureItem to = textures; to != null; to = to.next)
|
||||
TextureItem.uploadTexture(textures);
|
||||
|
||||
|
||||
if (!mReuseBitmap) {
|
||||
mBitmap.recycle();
|
||||
mBitmap = null;
|
||||
textures.bitmap = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clear() {
|
||||
|
||||
if (mBitmap != null) {
|
||||
if (!mReuseBitmap)
|
||||
mBitmap.recycle();
|
||||
|
||||
mBitmap = null;
|
||||
textures.bitmap = null;
|
||||
}
|
||||
|
||||
TextureItem.releaseTexture(textures);
|
||||
textures = null;
|
||||
|
||||
VertexItem.pool.releaseAll(vertexItems);
|
||||
vertexItems = null;
|
||||
}
|
||||
}
|
||||
136
src/org/oscim/renderer/sublayers/BitmapRenderer.java
Normal file
136
src/org/oscim/renderer/sublayers/BitmapRenderer.java
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2012, 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.sublayers;
|
||||
|
||||
import org.oscim.renderer.GLRenderer;
|
||||
import org.oscim.renderer.GLRenderer.Matrices;
|
||||
import org.oscim.renderer.GLState;
|
||||
import org.oscim.utils.GlUtils;
|
||||
|
||||
import android.opengl.GLES20;
|
||||
|
||||
// TODO merge with TextureRenderer
|
||||
|
||||
public final class BitmapRenderer {
|
||||
|
||||
//private final static String TAG = BitmapRenderer.class.getName();
|
||||
public final static boolean debug = true;
|
||||
|
||||
private static int mTextureProgram;
|
||||
private static int hTextureMVMatrix;
|
||||
private static int hTextureProjMatrix;
|
||||
private static int hTextureVertex;
|
||||
private static int hTextureScale;
|
||||
private static int hTextureScreenScale;
|
||||
private static int hTextureTexCoord;
|
||||
|
||||
public final static int INDICES_PER_SPRITE = 6;
|
||||
final static int VERTICES_PER_SPRITE = 4;
|
||||
final static int SHORTS_PER_VERTICE = 6;
|
||||
|
||||
static void init() {
|
||||
mTextureProgram = GlUtils.createProgram(textVertexShader,
|
||||
textFragmentShader);
|
||||
|
||||
hTextureMVMatrix = GLES20.glGetUniformLocation(mTextureProgram, "u_mv");
|
||||
hTextureProjMatrix = GLES20.glGetUniformLocation(mTextureProgram, "u_proj");
|
||||
hTextureScale = GLES20.glGetUniformLocation(mTextureProgram, "u_scale");
|
||||
hTextureScreenScale = GLES20.glGetUniformLocation(mTextureProgram, "u_swidth");
|
||||
hTextureVertex = GLES20.glGetAttribLocation(mTextureProgram, "vertex");
|
||||
hTextureTexCoord = GLES20.glGetAttribLocation(mTextureProgram, "tex_coord");
|
||||
}
|
||||
|
||||
public static Layer draw(Layer layer, float scale, Matrices m) {
|
||||
GLState.test(false, false);
|
||||
GLState.blend(true);
|
||||
|
||||
GLState.useProgram(mTextureProgram);
|
||||
|
||||
GLState.enableVertexArrays(hTextureTexCoord, hTextureVertex);
|
||||
|
||||
TextureLayer tl = (TextureLayer) layer;
|
||||
|
||||
if (tl.fixed)
|
||||
GLES20.glUniform1f(hTextureScale, (float) Math.sqrt(scale));
|
||||
else
|
||||
GLES20.glUniform1f(hTextureScale, 1);
|
||||
|
||||
GLES20.glUniform1f(hTextureScreenScale, 1f / GLRenderer.screenWidth);
|
||||
|
||||
m.proj.setAsUniform(hTextureProjMatrix);
|
||||
|
||||
m.mvp.setAsUniform(hTextureMVMatrix);
|
||||
|
||||
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, GLRenderer.mQuadIndicesID);
|
||||
|
||||
for (TextureItem ti = tl.textures; ti != null; ti = ti.next) {
|
||||
//Log.d(TAG, "render texture " + ti.id);
|
||||
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, ti.id);
|
||||
int maxVertices = GLRenderer.maxQuads * INDICES_PER_SPRITE;
|
||||
|
||||
// draw up to maxVertices in each iteration
|
||||
for (int i = 0; i < ti.vertices; i += maxVertices) {
|
||||
// to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8)
|
||||
int off = (ti.offset + i) * 8 + tl.offset;
|
||||
|
||||
GLES20.glVertexAttribPointer(hTextureVertex, 4,
|
||||
GLES20.GL_SHORT, false, 12, off);
|
||||
|
||||
GLES20.glVertexAttribPointer(hTextureTexCoord, 2,
|
||||
GLES20.GL_SHORT, false, 12, off + 8);
|
||||
|
||||
int numVertices = ti.vertices - i;
|
||||
if (numVertices > maxVertices)
|
||||
numVertices = maxVertices;
|
||||
|
||||
GLES20.glDrawElements(GLES20.GL_TRIANGLES, numVertices,
|
||||
GLES20.GL_UNSIGNED_SHORT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
return layer.next;
|
||||
}
|
||||
|
||||
//private final static double TEX_COORD_DIV = 1.0 / (1024 * COORD_SCALE);
|
||||
//private final static double COORD_DIV = 1.0 / GLRenderer.COORD_SCALE;
|
||||
|
||||
private final static String textVertexShader = ""
|
||||
+ "precision mediump float; "
|
||||
+ "attribute vec4 vertex;"
|
||||
+ "attribute vec2 tex_coord;"
|
||||
+ "uniform mat4 u_mv;"
|
||||
+ "uniform mat4 u_proj;"
|
||||
+ "uniform float u_scale;"
|
||||
+ "uniform float u_swidth;"
|
||||
+ "varying vec2 tex_c;"
|
||||
//+ "const vec2 div = vec2(" + TEX_COORD_DIV + "," + TEX_COORD_DIV + ");"
|
||||
//+ "const float coord_scale = " + COORD_DIV + ";"
|
||||
+ "void main() {"
|
||||
+ " gl_Position = u_mv * vec4(vertex.xy, 0.0, 1.0);"
|
||||
+ " tex_c = tex_coord;" // * div;"
|
||||
+ "}";
|
||||
|
||||
private final static String textFragmentShader = ""
|
||||
+ "precision mediump float;"
|
||||
+ "uniform sampler2D tex;"
|
||||
+ "varying vec2 tex_c;"
|
||||
+ "void main() {"
|
||||
+ " gl_FragColor = texture2D(tex, tex_c.xy);"
|
||||
+ "}";
|
||||
}
|
||||
513
src/org/oscim/renderer/sublayers/ExtrusionLayer.java
Normal file
513
src/org/oscim/renderer/sublayers/ExtrusionLayer.java
Normal file
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
* Copyright 2012, 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.sublayers;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import org.oscim.core.GeometryBuffer;
|
||||
import org.oscim.core.MapElement;
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.renderer.BufferObject;
|
||||
import org.oscim.renderer.GLRenderer;
|
||||
import org.oscim.utils.LineClipper;
|
||||
import org.oscim.view.MapView;
|
||||
|
||||
import android.opengl.GLES20;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* @author Hannes Janetzek
|
||||
* FIXME check if polygon has self intersections or 0/180 degree
|
||||
* angles! or bad things might happen in Triangle
|
||||
*/
|
||||
public class ExtrusionLayer extends Layer {
|
||||
private final static String TAG = ExtrusionLayer.class.getName();
|
||||
private static final float S = GLRenderer.COORD_SCALE;
|
||||
private VertexItem mVertices;
|
||||
private VertexItem mCurVertices;
|
||||
private VertexItem mIndices[];
|
||||
private final VertexItem mCurIndices[];
|
||||
private LineClipper mClipper;
|
||||
|
||||
// indices for:
|
||||
// 0. even sides, 1. odd sides, 2. roof, 3. roof outline
|
||||
public int mIndiceCnt[] = { 0, 0, 0, 0 };
|
||||
public int mNumIndices = 0;
|
||||
public int mNumVertices = 0;
|
||||
|
||||
public BufferObject vboIndices;
|
||||
public BufferObject vboVertices;
|
||||
|
||||
//private final static int IND_EVEN_SIDE = 0;
|
||||
//private final static int IND_ODD_SIDE = 1;
|
||||
private final static int IND_ROOF = 2;
|
||||
private final static int IND_OUTLINE = 3;
|
||||
|
||||
public boolean compiled = false;
|
||||
private final float mGroundResolution;
|
||||
|
||||
public ExtrusionLayer(int level, float groundResolution) {
|
||||
this.type = Layer.EXTRUSION;
|
||||
this.level = level;
|
||||
|
||||
mGroundResolution = groundResolution;
|
||||
mVertices = mCurVertices = VertexItem.pool.get();
|
||||
|
||||
mIndices = new VertexItem[4];
|
||||
mCurIndices = new VertexItem[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
mIndices[i] = mCurIndices[i] = VertexItem.pool.get();
|
||||
|
||||
mClipper = new LineClipper(0, 0, Tile.SIZE, Tile.SIZE);
|
||||
}
|
||||
|
||||
public void addBuildings(MapElement element) {
|
||||
|
||||
short[] index = element.index;
|
||||
float[] points = element.points;
|
||||
|
||||
float height = element.height;
|
||||
float minHeight = element.minHeight;
|
||||
|
||||
// 12m default
|
||||
if (height == 0)
|
||||
height = 12 * 100;
|
||||
|
||||
// 10 cm steps
|
||||
float sfactor = 1 / 10f;
|
||||
height *= sfactor;
|
||||
minHeight *= sfactor;
|
||||
|
||||
// match height with ground resultion
|
||||
// (meter per pixel)
|
||||
height /= mGroundResolution;
|
||||
minHeight /= mGroundResolution;
|
||||
|
||||
// my preference
|
||||
height *= 0.85;
|
||||
minHeight *= 0.85;
|
||||
|
||||
int length = 0, ipos = 0, ppos = 0;
|
||||
|
||||
boolean complexOutline = false;
|
||||
int geomIndexPos = 0;
|
||||
int geomPointPos = 0;
|
||||
|
||||
boolean simpleOutline = true;
|
||||
|
||||
// current vertex id
|
||||
int startVertex = mNumVertices;
|
||||
|
||||
for (int n = index.length; ipos < n; ipos++, ppos += length) {
|
||||
length = index[ipos];
|
||||
|
||||
// end marker
|
||||
if (length < 0)
|
||||
break;
|
||||
|
||||
// start next polygon
|
||||
if (length == 0) {
|
||||
if (complexOutline)
|
||||
addRoof(startVertex, element, geomIndexPos, geomPointPos);
|
||||
|
||||
startVertex = mNumVertices;
|
||||
simpleOutline = true;
|
||||
complexOutline = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check: drop last point from explicitly closed rings
|
||||
int len = length;
|
||||
if (!MapView.enableClosePolygons) {
|
||||
len -= 2;
|
||||
} else if (points[ppos] == points[ppos + len - 2]
|
||||
&& points[ppos + 1] == points[ppos + len - 1]) {
|
||||
// vector-tile-map does not produce implicty closed
|
||||
// polygons (yet)
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
// need at least three points
|
||||
if (len < 6)
|
||||
continue;
|
||||
|
||||
// check if polygon contains inner rings
|
||||
if (simpleOutline && (ipos < n - 1) && (index[ipos + 1] > 0))
|
||||
simpleOutline = false;
|
||||
|
||||
boolean convex = addOutline(points, ppos, len, minHeight, height, simpleOutline);
|
||||
|
||||
if (simpleOutline && (convex || len <= 8))
|
||||
addRoofSimple(startVertex, len);
|
||||
else if (!complexOutline) {
|
||||
complexOutline = true;
|
||||
// keep start postion of polygon and defer roof building
|
||||
// as it modifies the geometry array.
|
||||
geomIndexPos = ipos;
|
||||
geomPointPos = ppos;
|
||||
}
|
||||
}
|
||||
if (complexOutline)
|
||||
addRoof(startVertex, element, geomIndexPos, geomPointPos);
|
||||
}
|
||||
|
||||
private void addRoofSimple(int startVertex, int len) {
|
||||
|
||||
// roof indices for convex shapes
|
||||
int i = mCurIndices[IND_ROOF].used;
|
||||
short[] indices = mCurIndices[IND_ROOF].vertices;
|
||||
short first = (short) (startVertex + 1);
|
||||
|
||||
for (int k = 0; k < len - 4; k += 2) {
|
||||
if (i == VertexItem.SIZE) {
|
||||
mCurIndices[IND_ROOF].used = VertexItem.SIZE;
|
||||
mCurIndices[IND_ROOF].next = VertexItem.pool.get();
|
||||
mCurIndices[IND_ROOF] = mCurIndices[2].next;
|
||||
indices = mCurIndices[IND_ROOF].vertices;
|
||||
i = 0;
|
||||
}
|
||||
indices[i++] = first;
|
||||
indices[i++] = (short) (first + k + 2);
|
||||
indices[i++] = (short) (first + k + 4);
|
||||
}
|
||||
mCurIndices[IND_ROOF].used = i;
|
||||
}
|
||||
|
||||
private void addRoof(int startVertex, GeometryBuffer geom, int ipos, int ppos) {
|
||||
short[] index = geom.index;
|
||||
float[] points = geom.points;
|
||||
|
||||
int len = 0;
|
||||
int rings = 0;
|
||||
|
||||
// get sum of points in polygon
|
||||
for (int i = ipos, n = index.length; i < n && index[i] > 0; i++) {
|
||||
len += index[i];
|
||||
rings++;
|
||||
}
|
||||
|
||||
// triangulate up to 600 points (limited only by prepared buffers)
|
||||
// some buildings in paris have even more...
|
||||
if (len > 1200) {
|
||||
Log.d(TAG, ">>> skip building : " + len + " <<<");
|
||||
return;
|
||||
}
|
||||
|
||||
int used = triangulate(points, ppos, len, index, ipos, rings,
|
||||
startVertex + 1, mCurIndices[IND_ROOF]);
|
||||
|
||||
if (used > 0) {
|
||||
// get back to the last item added..
|
||||
VertexItem it = mIndices[IND_ROOF];
|
||||
while (it.next != null)
|
||||
it = it.next;
|
||||
mCurIndices[IND_ROOF] = it;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean addOutline(float[] points, int pos, int len, float minHeight, float height,
|
||||
boolean convex) {
|
||||
|
||||
// add two vertices for last face to make zigzag indices work
|
||||
boolean addFace = (len % 4 != 0);
|
||||
int vertexCnt = len + (addFace ? 2 : 0);
|
||||
|
||||
short h = (short) height;
|
||||
short mh = (short) minHeight;
|
||||
|
||||
float cx = points[pos + len - 2];
|
||||
float cy = points[pos + len - 1];
|
||||
float nx = points[pos + 0];
|
||||
float ny = points[pos + 1];
|
||||
|
||||
// vector to next point
|
||||
float vx = nx - cx;
|
||||
float vy = ny - cy;
|
||||
// vector from previous point
|
||||
float ux, uy;
|
||||
|
||||
float a = (float) Math.sqrt(vx * vx + vy * vy);
|
||||
short color1 = (short) ((1 + vx / a) * 127);
|
||||
short fcolor = color1;
|
||||
short color2 = 0;
|
||||
|
||||
int even = 0;
|
||||
int changeX = 0;
|
||||
int changeY = 0;
|
||||
|
||||
// vertex offset for all vertices in layer
|
||||
int vOffset = mNumVertices;
|
||||
|
||||
short[] vertices = mCurVertices.vertices;
|
||||
int v = mCurVertices.used;
|
||||
|
||||
mClipper.clipStart((int) nx, (int) ny);
|
||||
|
||||
for (int i = 2, n = vertexCnt + 2; i < n; i += 2, v += 8) {
|
||||
cx = nx;
|
||||
cy = ny;
|
||||
|
||||
ux = vx;
|
||||
uy = vy;
|
||||
|
||||
/* add bottom and top vertex for each point */
|
||||
if (v == VertexItem.SIZE) {
|
||||
mCurVertices.used = VertexItem.SIZE;
|
||||
mCurVertices.next = VertexItem.pool.get();
|
||||
mCurVertices = mCurVertices.next;
|
||||
vertices = mCurVertices.vertices;
|
||||
v = 0;
|
||||
}
|
||||
|
||||
// set coordinate
|
||||
vertices[v + 0] = vertices[v + 4] = (short) (cx * S);
|
||||
vertices[v + 1] = vertices[v + 5] = (short) (cy * S);
|
||||
|
||||
// set height
|
||||
vertices[v + 2] = mh;
|
||||
vertices[v + 6] = h;
|
||||
|
||||
// get direction to next point
|
||||
if (i < len) {
|
||||
nx = points[pos + i + 0];
|
||||
ny = points[pos + i + 1];
|
||||
} else if (i == len) {
|
||||
nx = points[pos + 0];
|
||||
ny = points[pos + 1];
|
||||
} else { // if (addFace)
|
||||
short c = (short) (color1 | fcolor << 8);
|
||||
vertices[v + 3] = vertices[v + 7] = c;
|
||||
v += 8;
|
||||
break;
|
||||
}
|
||||
|
||||
vx = nx - cx;
|
||||
vy = ny - cy;
|
||||
|
||||
// set lighting (by direction)
|
||||
a = (float) Math.sqrt(vx * vx + vy * vy);
|
||||
color2 = (short) ((1 + vx / a) * 127);
|
||||
|
||||
short c;
|
||||
if (even == 0)
|
||||
c = (short) (color1 | color2 << 8);
|
||||
else
|
||||
c = (short) (color2 | color1 << 8);
|
||||
|
||||
vertices[v + 3] = vertices[v + 7] = c;
|
||||
color1 = color2;
|
||||
|
||||
/* check if polygon is convex */
|
||||
if (convex) {
|
||||
// TODO simple polys with only one concave arc
|
||||
// could be handled without special triangulation
|
||||
if ((ux < 0 ? 1 : -1) != (vx < 0 ? 1 : -1))
|
||||
changeX++;
|
||||
if ((uy < 0 ? 1 : -1) != (vy < 0 ? 1 : -1))
|
||||
changeY++;
|
||||
|
||||
if (changeX > 2 || changeY > 2)
|
||||
convex = false;
|
||||
}
|
||||
|
||||
/* check if face is within tile */
|
||||
if (mClipper.clipNext((int) nx, (int) ny) == 0) {
|
||||
even = (even == 0 ? 1 : 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* add ZigZagQuadIndices(tm) for sides */
|
||||
short vert = (short) (vOffset + (i - 2));
|
||||
short s0 = vert++;
|
||||
short s1 = vert++;
|
||||
short s2 = vert++;
|
||||
short s3 = vert++;
|
||||
|
||||
// connect last to first (when number of faces is even)
|
||||
if (!addFace && i == len) {
|
||||
s2 -= len;
|
||||
s3 -= len;
|
||||
}
|
||||
|
||||
short[] indices = mCurIndices[even].vertices;
|
||||
// index id relative to mCurIndices item
|
||||
int ind = mCurIndices[even].used;
|
||||
|
||||
if (ind == VertexItem.SIZE) {
|
||||
mCurIndices[even].next = VertexItem.pool.get();
|
||||
mCurIndices[even] = mCurIndices[even].next;
|
||||
indices = mCurIndices[even].vertices;
|
||||
ind = 0;
|
||||
}
|
||||
|
||||
indices[ind + 0] = s0;
|
||||
indices[ind + 1] = s2;
|
||||
indices[ind + 2] = s1;
|
||||
|
||||
indices[ind + 3] = s1;
|
||||
indices[ind + 4] = s2;
|
||||
indices[ind + 5] = s3;
|
||||
|
||||
mCurIndices[even].used += 6;
|
||||
even = (even == 0 ? 1 : 0);
|
||||
|
||||
/* add roof outline indices */
|
||||
VertexItem it = mCurIndices[IND_OUTLINE];
|
||||
if (it.used == VertexItem.SIZE) {
|
||||
it.next = VertexItem.pool.get();
|
||||
it = mCurIndices[IND_OUTLINE] = it.next;
|
||||
}
|
||||
it.vertices[it.used++] = s1;
|
||||
it.vertices[it.used++] = s3;
|
||||
}
|
||||
|
||||
mCurVertices.used = v;
|
||||
mNumVertices += vertexCnt;
|
||||
return convex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compile(ShortBuffer sbuf) {
|
||||
|
||||
if (mNumVertices == 0 || compiled)
|
||||
return;
|
||||
|
||||
vboVertices = BufferObject.get(0);
|
||||
vboIndices = BufferObject.get(0);
|
||||
|
||||
// upload indices
|
||||
//sbuf.clear();
|
||||
|
||||
mNumIndices = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (VertexItem vi = mIndices[i]; vi != null; vi = vi.next) {
|
||||
sbuf.put(vi.vertices, 0, vi.used);
|
||||
mIndiceCnt[i] += vi.used;
|
||||
}
|
||||
mNumIndices += mIndiceCnt[i];
|
||||
}
|
||||
|
||||
sbuf.flip();
|
||||
vboIndices.size = mNumIndices * 2;
|
||||
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, vboIndices.id);
|
||||
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER,
|
||||
vboIndices.size, sbuf, GLES20.GL_DYNAMIC_DRAW);
|
||||
|
||||
// upload vertices
|
||||
sbuf.clear();
|
||||
for (VertexItem vi = mVertices; vi != null; vi = vi.next)
|
||||
sbuf.put(vi.vertices, 0, vi.used);
|
||||
|
||||
sbuf.flip();
|
||||
vboVertices.size = mNumVertices * 4 * 2;
|
||||
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboVertices.id);
|
||||
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
|
||||
vboVertices.size, sbuf, GLES20.GL_DYNAMIC_DRAW);
|
||||
|
||||
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
VertexItem.pool.releaseAll(mIndices[i]);
|
||||
|
||||
VertexItem.pool.releaseAll(mVertices);
|
||||
|
||||
mIndices = null;
|
||||
mVertices = null;
|
||||
mClipper = null;
|
||||
|
||||
compiled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clear() {
|
||||
if (compiled) {
|
||||
BufferObject.release(vboIndices);
|
||||
BufferObject.release(vboVertices);
|
||||
vboIndices = null;
|
||||
vboVertices = null;
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++)
|
||||
VertexItem.pool.releaseAll(mIndices[i]);
|
||||
mIndices = null;
|
||||
|
||||
VertexItem.pool.releaseAll(mVertices);
|
||||
mVertices = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean initialized = false;
|
||||
private static ShortBuffer sBuf;
|
||||
|
||||
public static synchronized int triangulate(float[] points, int ppos, int plen, short[] index,
|
||||
int ipos, int rings, int vertexOffset, VertexItem item) {
|
||||
|
||||
if (!initialized) {
|
||||
// FIXME also cleanup on shutdown!
|
||||
sBuf = ByteBuffer.allocateDirect(1800 * 2).order(ByteOrder.nativeOrder())
|
||||
.asShortBuffer();
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
sBuf.clear();
|
||||
sBuf.put(index, ipos, rings);
|
||||
|
||||
int numTris = triangulate(points, ppos, plen, rings, sBuf, vertexOffset);
|
||||
|
||||
int numIndices = numTris * 3;
|
||||
sBuf.limit(numIndices);
|
||||
sBuf.position(0);
|
||||
|
||||
for (int k = 0, cnt = 0; k < numIndices; k += cnt) {
|
||||
|
||||
if (item.used == VertexItem.SIZE) {
|
||||
item.next = VertexItem.pool.get();
|
||||
item = item.next;
|
||||
}
|
||||
|
||||
cnt = VertexItem.SIZE - item.used;
|
||||
|
||||
if (k + cnt > numIndices)
|
||||
cnt = numIndices - k;
|
||||
|
||||
sBuf.get(item.vertices, item.used, cnt);
|
||||
item.used += cnt;
|
||||
}
|
||||
|
||||
return numIndices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param points an array of x,y coordinates
|
||||
* @param pos position in points array
|
||||
* @param len number of points * 2 (i.e. values to read)
|
||||
* @param numRings number of rings in polygon == outer(1) + inner rings
|
||||
* @param io input: number of points in rings - times 2!
|
||||
* output: indices of triangles, 3 per triangle :) (indices use
|
||||
* stride=2, i.e. 0,2,4...)
|
||||
* @param ioffset offset used to add offset to indices
|
||||
* @return number of triangles in io buffer
|
||||
*/
|
||||
public static native int triangulate(float[] points, int pos, int len, int numRings,
|
||||
ShortBuffer io,
|
||||
int ioffset);
|
||||
|
||||
static {
|
||||
System.loadLibrary("triangle");
|
||||
}
|
||||
}
|
||||
52
src/org/oscim/renderer/sublayers/Layer.java
Normal file
52
src/org/oscim/renderer/sublayers/Layer.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2012, 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.sublayers;
|
||||
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import org.oscim.utils.pool.Inlist;
|
||||
/**
|
||||
* @authorHannes Janetzek
|
||||
*/
|
||||
public abstract class Layer extends Inlist<Layer>{
|
||||
public final static byte LINE = 0;
|
||||
public final static byte POLYGON = 1;
|
||||
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;
|
||||
|
||||
// drawing order from bottom to top
|
||||
int level;
|
||||
|
||||
// number of vertices for this layer
|
||||
public int verticesCnt;
|
||||
|
||||
// in case of line and polygon layer:
|
||||
// - number of VERTICES offset for this layertype in VBO
|
||||
// otherwise:
|
||||
// - offset in byte in VBO
|
||||
public int offset;
|
||||
|
||||
VertexItem vertexItems;
|
||||
protected VertexItem curItem;
|
||||
|
||||
abstract protected void compile(ShortBuffer sbuf);
|
||||
abstract protected void clear();
|
||||
}
|
||||
319
src/org/oscim/renderer/sublayers/Layers.java
Normal file
319
src/org/oscim/renderer/sublayers/Layers.java
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright 2012, 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.sublayers;
|
||||
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import org.oscim.renderer.BufferObject;
|
||||
import org.oscim.theme.renderinstruction.Line;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class Layers {
|
||||
private final static String TAG = Layers.class.getName();
|
||||
|
||||
public static void initRenderer() {
|
||||
LineRenderer.init();
|
||||
LineTexRenderer.init();
|
||||
PolygonRenderer.init();
|
||||
TextureRenderer.init();
|
||||
BitmapRenderer.init();
|
||||
|
||||
TextureItem.init(10);
|
||||
}
|
||||
|
||||
// mixed Polygon- and LineLayer
|
||||
public Layer baseLayers;
|
||||
// Text- and SymbolLayer
|
||||
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
|
||||
public long time;
|
||||
|
||||
private Layer mCurLayer;
|
||||
|
||||
/**
|
||||
* add the LineLayer for a level with a given Line style. Levels are
|
||||
* ordered from bottom (0) to top
|
||||
*/
|
||||
public LineLayer addLineLayer(int level, Line style) {
|
||||
LineLayer ll = (LineLayer) getLayer(level, Layer.LINE);
|
||||
if (ll == null)
|
||||
return null;
|
||||
|
||||
ll.width = style.width;
|
||||
ll.line = style;
|
||||
|
||||
return ll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or add the LineLayer for a level. Levels are ordered from
|
||||
* bottom (0) to top
|
||||
*/
|
||||
public LineLayer getLineLayer(int level) {
|
||||
return (LineLayer) getLayer(level, Layer.LINE);
|
||||
}
|
||||
/**
|
||||
* Get or add the PolygonLayer for a level. Levels are ordered from
|
||||
* bottom (0) to top
|
||||
*/
|
||||
|
||||
public PolygonLayer getPolygonLayer(int level) {
|
||||
return (PolygonLayer) getLayer(level, Layer.POLYGON);
|
||||
}
|
||||
/**
|
||||
* Get or add the TexLineLayer for a level. Levels are ordered from
|
||||
* bottom (0) to top
|
||||
*/
|
||||
|
||||
public LineTexLayer getLineTexLayer(int level) {
|
||||
return (LineTexLayer) getLayer(level, Layer.TEXLINE);
|
||||
}
|
||||
|
||||
public TextLayer addTextLayer(TextLayer textLayer) {
|
||||
textLayer.next = textureLayers;
|
||||
textureLayers = textLayer;
|
||||
return textLayer;
|
||||
}
|
||||
|
||||
private Layer getLayer(int level, byte type) {
|
||||
Layer l = baseLayers;
|
||||
Layer layer = null;
|
||||
|
||||
if (mCurLayer != null && mCurLayer.level == level) {
|
||||
layer = mCurLayer;
|
||||
} else {
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
mCurLayer = layer;
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
private final static int[] VERTEX_SHORT_CNT = {
|
||||
4, // LINE_VERTEX_SHORTS
|
||||
2, // POLY_VERTEX_SHORTS
|
||||
6, // TEXLINE_VERTEX_SHORTS
|
||||
};
|
||||
|
||||
private final static int TEXTURE_VERTEX_SHORTS = 6;
|
||||
|
||||
private final static int SHORT_BYTES = 2;
|
||||
|
||||
public int getSize() {
|
||||
int size = 0;
|
||||
|
||||
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;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public void compile(ShortBuffer sbuf, boolean addFill) {
|
||||
// offset from fill coordinates
|
||||
int pos = 0;
|
||||
int size = 0;
|
||||
|
||||
if (addFill) {
|
||||
pos = 4;
|
||||
size = 8;
|
||||
}
|
||||
|
||||
size += addLayerItems(sbuf, baseLayers, Layer.POLYGON, pos);
|
||||
|
||||
lineOffset = size * SHORT_BYTES;
|
||||
size += addLayerItems(sbuf, baseLayers, Layer.LINE, 0);
|
||||
|
||||
texLineOffset = size * SHORT_BYTES;
|
||||
for (Layer l = baseLayers; l != null; l = l.next) {
|
||||
if (l.type == Layer.TEXLINE) {
|
||||
addPoolItems(l, sbuf);
|
||||
// add additional vertex for interleaving,
|
||||
// see TexLineLayer.
|
||||
sbuf.position(sbuf.position() + 6);
|
||||
}
|
||||
}
|
||||
|
||||
for (Layer l = textureLayers; l != null; l = l.next) {
|
||||
TextureLayer tl = (TextureLayer) l;
|
||||
tl.compile(sbuf);
|
||||
}
|
||||
|
||||
// extrusion layers are compiled by extrusion overlay
|
||||
// for (Layer l = extrusionLayers; l != null; l = l.next) {
|
||||
// ExtrusionLayer tl = (ExtrusionLayer) l;
|
||||
// tl.compile(sbuf);
|
||||
// }
|
||||
}
|
||||
|
||||
// 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) {
|
||||
VertexItem last = null, items = null;
|
||||
int size = 0;
|
||||
|
||||
for (; l != null; l = l.next) {
|
||||
if (l.type != type)
|
||||
continue;
|
||||
|
||||
for (VertexItem it = l.vertexItems; it != null; it = it.next) {
|
||||
if (it.next == null) {
|
||||
size += it.used;
|
||||
sbuf.put(it.vertices, 0, it.used);
|
||||
}
|
||||
else {
|
||||
size += VertexItem.SIZE;
|
||||
sbuf.put(it.vertices, 0, VertexItem.SIZE);
|
||||
}
|
||||
last = it;
|
||||
}
|
||||
if (last == null)
|
||||
continue;
|
||||
|
||||
l.offset = pos;
|
||||
|
||||
pos += l.verticesCnt;
|
||||
|
||||
last.next = items;
|
||||
items = l.vertexItems;
|
||||
last = null;
|
||||
|
||||
l.vertexItems = null;
|
||||
l.curItem = null;
|
||||
}
|
||||
VertexItem.pool.releaseAll(items);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void addPoolItems(Layer l, ShortBuffer sbuf) {
|
||||
// offset of layer data in vbo
|
||||
l.offset = sbuf.position() * SHORT_BYTES;
|
||||
|
||||
for (VertexItem it = l.vertexItems; it != null; it = it.next) {
|
||||
if (it.next == null)
|
||||
sbuf.put(it.vertices, 0, it.used);
|
||||
else
|
||||
sbuf.put(it.vertices, 0, VertexItem.SIZE);
|
||||
}
|
||||
|
||||
VertexItem.pool.releaseAll(l.vertexItems);
|
||||
l.vertexItems = null;
|
||||
}
|
||||
|
||||
// cleanup only when layers are not used by tile or overlay anymore!
|
||||
public void clear() {
|
||||
|
||||
// clear line and polygon layers directly
|
||||
Layer l = baseLayers;
|
||||
while (l != null) {
|
||||
if (l.vertexItems != null) {
|
||||
VertexItem.pool.releaseAll(l.vertexItems);
|
||||
l.vertexItems = null;
|
||||
l.curItem = null;
|
||||
}
|
||||
l.verticesCnt = 0;
|
||||
l = l.next;
|
||||
}
|
||||
|
||||
for (l = textureLayers; l != null; l = l.next) {
|
||||
l.clear();
|
||||
}
|
||||
|
||||
for (l = extrusionLayers; l != null; l = l.next) {
|
||||
l.clear();
|
||||
}
|
||||
baseLayers = null;
|
||||
textureLayers = null;
|
||||
extrusionLayers = null;
|
||||
mCurLayer = null;
|
||||
// if (vbo != null){
|
||||
// BufferObject.release(vbo);
|
||||
// vbo = null;
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
572
src/org/oscim/renderer/sublayers/LineLayer.java
Normal file
572
src/org/oscim/renderer/sublayers/LineLayer.java
Normal file
@@ -0,0 +1,572 @@
|
||||
/*
|
||||
* 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.renderer.sublayers;
|
||||
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import org.oscim.core.GeometryBuffer;
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.graphics.Paint.Cap;
|
||||
import org.oscim.renderer.GLRenderer;
|
||||
import org.oscim.theme.renderinstruction.Line;
|
||||
import org.oscim.utils.FastMath;
|
||||
import org.oscim.view.MapView;
|
||||
|
||||
/**
|
||||
*/
|
||||
public final class LineLayer extends Layer {
|
||||
private static final float COORD_SCALE = GLRenderer.COORD_SCALE;
|
||||
// scale factor mapping extrusion vector to short values
|
||||
public static final float DIR_SCALE = 2048;
|
||||
// mask for packing last two bits of extrusion vector with texture
|
||||
// coordinates
|
||||
private static final int DIR_MASK = 0xFFFFFFFC;
|
||||
|
||||
// lines referenced by this outline layer
|
||||
public LineLayer outlines;
|
||||
public Line line;
|
||||
public float width;
|
||||
|
||||
public boolean roundCap;
|
||||
|
||||
LineLayer(int layer) {
|
||||
this.level = layer;
|
||||
this.type = Layer.LINE;
|
||||
}
|
||||
|
||||
public void addOutline(LineLayer link) {
|
||||
for (LineLayer l = outlines; l != null; l = l.outlines)
|
||||
if (link == l)
|
||||
return;
|
||||
|
||||
link.outlines = outlines;
|
||||
outlines = link;
|
||||
}
|
||||
|
||||
/**
|
||||
* line extrusion is based on code from GLMap
|
||||
* (https://github.com/olofsj/GLMap/)
|
||||
*
|
||||
* @param points
|
||||
* array of points as x,y pairs.
|
||||
* @param index
|
||||
* array of indices holding the length of the individual
|
||||
* line coordinates (i.e. points * 2).
|
||||
* when index is null one a line with points.length
|
||||
* is assumed.
|
||||
* @param closed
|
||||
* whether to connect start- and end-point.
|
||||
*/
|
||||
public void addLine(float[] points, short[] index, boolean closed) {
|
||||
addLine(points, index, -1, closed);
|
||||
}
|
||||
|
||||
public void addLine(GeometryBuffer geom) {
|
||||
if (geom.isPoly())
|
||||
addLine(geom.points, geom.index, -1, true);
|
||||
else if (geom.isLine())
|
||||
addLine(geom.points, geom.index, -1, false);
|
||||
}
|
||||
|
||||
public void addLine(float[] points, int numPoints, boolean closed) {
|
||||
if (numPoints >= 4)
|
||||
addLine(points, null, numPoints, closed);
|
||||
}
|
||||
|
||||
private void addLine(float[] points, short[] index, int numPoints, boolean closed) {
|
||||
float x, y, nextX, nextY;
|
||||
float a, ux, uy, vx, vy, wx, wy;
|
||||
|
||||
int tmax = Tile.SIZE + 4;
|
||||
int tmin = -4;
|
||||
|
||||
boolean rounded = false;
|
||||
boolean squared = false;
|
||||
|
||||
if (line.cap == Cap.ROUND)
|
||||
rounded = true;
|
||||
else if (line.cap == Cap.SQUARE)
|
||||
squared = true;
|
||||
|
||||
if (vertexItems == null)
|
||||
curItem = vertexItems = VertexItem.pool.get();
|
||||
|
||||
VertexItem si = curItem;
|
||||
short v[] = si.vertices;
|
||||
int opos = si.used;
|
||||
|
||||
// FIXME: remove this when switching to oscimap MapDatabase
|
||||
if (!MapView.enableClosePolygons)
|
||||
closed = false;
|
||||
|
||||
// Note: just a hack to save some vertices, when there are more than 200 lines
|
||||
// per type
|
||||
if (rounded) {
|
||||
int cnt = 0;
|
||||
for (int i = 0, n = index.length; i < n; i++, cnt++) {
|
||||
if (index[i] < 0)
|
||||
break;
|
||||
if (cnt > 400) {
|
||||
rounded = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
roundCap = rounded;
|
||||
|
||||
int n;
|
||||
int length = 0;
|
||||
|
||||
if (index == null) {
|
||||
n = 1;
|
||||
if (numPoints > 0) {
|
||||
length = numPoints;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
// amount of vertices used
|
||||
// + 2 for drawing triangle-strip
|
||||
// + 4 for round caps
|
||||
// + 2 for closing polygons
|
||||
verticesCnt += length + (rounded ? 6 : 2) + (closed ? 2 : 0);
|
||||
|
||||
int ipos = pos;
|
||||
|
||||
x = points[ipos++];
|
||||
y = points[ipos++];
|
||||
|
||||
nextX = points[ipos++];
|
||||
nextY = points[ipos++];
|
||||
|
||||
// Calculate triangle corners for the given width
|
||||
vx = nextX - x;
|
||||
vy = nextY - y;
|
||||
|
||||
// Unit vector to next node
|
||||
a = (float) Math.sqrt(vx * vx + vy * vy);
|
||||
vx /= a;
|
||||
vy /= a;
|
||||
|
||||
// perpendicular on the first segment
|
||||
ux = -vy;
|
||||
uy = vx;
|
||||
|
||||
int ddx, ddy;
|
||||
|
||||
// vertex point coordinate
|
||||
short ox = (short) (x * COORD_SCALE);
|
||||
short oy = (short) (y * COORD_SCALE);
|
||||
|
||||
// vertex extrusion vector, last two bit
|
||||
// encode texture coord.
|
||||
short dx, dy;
|
||||
|
||||
// when the endpoint is outside the tile region omit round caps.
|
||||
boolean outside = (x < tmin || x > tmax || y < tmin || y > tmax);
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
if (rounded && !outside) {
|
||||
// add first vertex twice
|
||||
ddx = (int) ((ux - vx) * DIR_SCALE);
|
||||
ddy = (int) ((uy - vy) * DIR_SCALE);
|
||||
dx = (short) (0 | ddx & DIR_MASK);
|
||||
dy = (short) (2 | ddy & DIR_MASK);
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = dx;
|
||||
v[opos++] = dy;
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = dx;
|
||||
v[opos++] = dy;
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
ddx = (int) (-(ux + vx) * DIR_SCALE);
|
||||
ddy = (int) (-(uy + vy) * DIR_SCALE);
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = (short) (2 | ddx & DIR_MASK);
|
||||
v[opos++] = (short) (2 | ddy & DIR_MASK);
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
// Start of line
|
||||
ddx = (int) (ux * DIR_SCALE);
|
||||
ddy = (int) (uy * DIR_SCALE);
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = (short) (0 | ddx & DIR_MASK);
|
||||
v[opos++] = (short) (1 | ddy & DIR_MASK);
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = (short) (2 | -ddx & DIR_MASK);
|
||||
v[opos++] = (short) (1 | -ddy & DIR_MASK);
|
||||
|
||||
} else {
|
||||
// outside means line is probably clipped
|
||||
// TODO should align ending with tile boundary
|
||||
// for now, just extend the line a little
|
||||
float tx = vx;
|
||||
float ty = vy;
|
||||
|
||||
if (squared) {
|
||||
tx = 0;
|
||||
ty = 0;
|
||||
} else if (!outside) {
|
||||
tx *= 0.5;
|
||||
ty *= 0.5;
|
||||
}
|
||||
|
||||
if (rounded)
|
||||
verticesCnt -= 2;
|
||||
|
||||
// add first vertex twice
|
||||
ddx = (int) ((ux - tx) * DIR_SCALE);
|
||||
ddy = (int) ((uy - ty) * DIR_SCALE);
|
||||
dx = (short) (0 | ddx & DIR_MASK);
|
||||
dy = (short) (1 | ddy & DIR_MASK);
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = dx;
|
||||
v[opos++] = dy;
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = dx;
|
||||
v[opos++] = dy;
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
ddx = (int) (-(ux + tx) * DIR_SCALE);
|
||||
ddy = (int) (-(uy + ty) * DIR_SCALE);
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = (short) (2 | ddx & DIR_MASK);
|
||||
v[opos++] = (short) (1 | ddy & DIR_MASK);
|
||||
|
||||
}
|
||||
|
||||
x = nextX;
|
||||
y = nextY;
|
||||
boolean flip = false;
|
||||
// Unit vector pointing back to previous node
|
||||
vx *= -1;
|
||||
vy *= -1;
|
||||
|
||||
int end = pos + length;
|
||||
|
||||
for (;;) {
|
||||
if (ipos < end) {
|
||||
nextX = points[ipos++];
|
||||
nextY = points[ipos++];
|
||||
} else if (closed && ipos < end + 2) {
|
||||
// add startpoint == endpoint
|
||||
nextX = points[pos];
|
||||
nextY = points[pos + 1];
|
||||
ipos += 2;
|
||||
} else
|
||||
break;
|
||||
|
||||
// Unit vector pointing forward to next node
|
||||
wx = nextX - x;
|
||||
wy = nextY - y;
|
||||
a = (float) Math.sqrt(wx * wx + wy * wy);
|
||||
wx /= a;
|
||||
wy /= a;
|
||||
|
||||
// Sum of these two vectors points
|
||||
ux = vx + wx;
|
||||
uy = vy + wy;
|
||||
|
||||
// cross-product
|
||||
a = wx * uy - wy * ux;
|
||||
|
||||
if (FastMath.abs(a) < 0.01f) {
|
||||
// Almost straight
|
||||
ux = -wy;
|
||||
uy = wx;
|
||||
} else {
|
||||
ux /= a;
|
||||
uy /= a;
|
||||
|
||||
// avoid miter going to infinity.
|
||||
// TODO add option for round joints
|
||||
if (FastMath.absMaxCmp(ux, uy, 4f)) {
|
||||
ux = vx - wx;
|
||||
uy = vy - wy;
|
||||
|
||||
a = -wy * ux + wx * uy;
|
||||
ux /= a;
|
||||
uy /= a;
|
||||
flip = !flip;
|
||||
}
|
||||
}
|
||||
|
||||
ox = (short) (x * COORD_SCALE);
|
||||
oy = (short) (y * COORD_SCALE);
|
||||
|
||||
ddx = (int) (ux * DIR_SCALE);
|
||||
ddy = (int) (uy * DIR_SCALE);
|
||||
|
||||
if (flip) {
|
||||
ddx = -ddx;
|
||||
ddy = -ddy;
|
||||
}
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = (short) (0 | ddx & DIR_MASK);
|
||||
v[opos++] = (short) (1 | ddy & DIR_MASK);
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = (short) (2 | -ddx & DIR_MASK);
|
||||
v[opos++] = (short) (1 | -ddy & DIR_MASK);
|
||||
|
||||
x = nextX;
|
||||
y = nextY;
|
||||
|
||||
// flip unit vector to point back
|
||||
vx = -wx;
|
||||
vy = -wy;
|
||||
}
|
||||
|
||||
ux = vy;
|
||||
uy = -vx;
|
||||
|
||||
outside = (x < tmin || x > tmax || y < tmin || y > tmax);
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si.next = VertexItem.pool.get();
|
||||
si = si.next;
|
||||
opos = 0;
|
||||
v = si.vertices;
|
||||
}
|
||||
|
||||
ox = (short) (x * COORD_SCALE);
|
||||
oy = (short) (y * COORD_SCALE);
|
||||
|
||||
if (rounded && !outside) {
|
||||
ddx = (int) (ux * DIR_SCALE);
|
||||
ddy = (int) (uy * DIR_SCALE);
|
||||
|
||||
if (flip) {
|
||||
ddx = -ddx;
|
||||
ddy = -ddy;
|
||||
}
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = (short) (0 | ddx & DIR_MASK);
|
||||
v[opos++] = (short) (1 | ddy & DIR_MASK);
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = (short) (2 | -ddx & DIR_MASK);
|
||||
v[opos++] = (short) (1 | -ddy & DIR_MASK);
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
// For rounded line edges
|
||||
ddx = (int) ((ux - vx) * DIR_SCALE);
|
||||
ddy = (int) ((uy - vy) * DIR_SCALE);
|
||||
|
||||
dx = (short) (0 | (flip ? -ddx : ddx) & DIR_MASK);
|
||||
dy = (short) (0 | (flip ? -ddy : ddy) & DIR_MASK);
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = dx;
|
||||
v[opos++] = dy;
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
// add last vertex twice
|
||||
ddx = (int) (-(ux + vx) * DIR_SCALE);
|
||||
ddy = (int) (-(uy + vy) * DIR_SCALE);
|
||||
dx = (short) (2 | (flip ? -ddx : ddx) & DIR_MASK);
|
||||
dy = (short) (0 | (flip ? -ddy : ddy) & DIR_MASK);
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = dx;
|
||||
v[opos++] = dy;
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = dx;
|
||||
v[opos++] = dy;
|
||||
|
||||
} else {
|
||||
if (squared) {
|
||||
vx = 0;
|
||||
vy = 0;
|
||||
} else if (!outside) {
|
||||
vx *= 0.5;
|
||||
vy *= 0.5;
|
||||
}
|
||||
|
||||
if (rounded)
|
||||
verticesCnt -= 2;
|
||||
|
||||
ddx = (int) ((ux - vx) * DIR_SCALE);
|
||||
ddy = (int) ((uy - vy) * DIR_SCALE);
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = (short) (0 | (flip ? -ddx : ddx) & DIR_MASK);
|
||||
v[opos++] = (short) (1 | (flip ? -ddy : ddy) & DIR_MASK);
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
// add last vertex twice
|
||||
ddx = (int) (-(ux + vx) * DIR_SCALE);
|
||||
ddy = (int) (-(uy + vy) * DIR_SCALE);
|
||||
dx = (short) (2 | (flip ? -ddx : ddx) & DIR_MASK);
|
||||
dy = (short) (1 | (flip ? -ddy : ddy) & DIR_MASK);
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = dx;
|
||||
v[opos++] = dy;
|
||||
|
||||
if (opos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
opos = 0;
|
||||
}
|
||||
|
||||
v[opos++] = ox;
|
||||
v[opos++] = oy;
|
||||
v[opos++] = dx;
|
||||
v[opos++] = dy;
|
||||
}
|
||||
pos += length;
|
||||
}
|
||||
|
||||
si.used = opos;
|
||||
curItem = si;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (vertexItems != null) {
|
||||
VertexItem.pool.releaseAll(vertexItems);
|
||||
vertexItems = null;
|
||||
curItem = null;
|
||||
}
|
||||
verticesCnt = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void compile(ShortBuffer sbuf) {
|
||||
}
|
||||
}
|
||||
387
src/org/oscim/renderer/sublayers/LineRenderer.java
Normal file
387
src/org/oscim/renderer/sublayers/LineRenderer.java
Normal file
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
* 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.renderer.sublayers;
|
||||
|
||||
import static android.opengl.GLES20.GL_SHORT;
|
||||
import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
|
||||
import static android.opengl.GLES20.glDrawArrays;
|
||||
import static android.opengl.GLES20.glGetAttribLocation;
|
||||
import static android.opengl.GLES20.glGetUniformLocation;
|
||||
import static android.opengl.GLES20.glUniform1f;
|
||||
import static android.opengl.GLES20.glVertexAttribPointer;
|
||||
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.renderer.GLRenderer;
|
||||
import org.oscim.renderer.GLRenderer.Matrices;
|
||||
import org.oscim.renderer.GLState;
|
||||
import org.oscim.theme.renderinstruction.Line;
|
||||
import org.oscim.utils.GlUtils;
|
||||
|
||||
import android.opengl.GLES20;
|
||||
import android.util.Log;
|
||||
|
||||
public final class LineRenderer {
|
||||
private final static String TAG = LineRenderer.class.getName();
|
||||
|
||||
private static final int LINE_VERTICES_DATA_POS_OFFSET = 0;
|
||||
|
||||
// factor to normalize extrusion vector and scale to coord scale
|
||||
private final static float COORD_SCALE_BY_DIR_SCALE =
|
||||
GLRenderer.COORD_SCALE / LineLayer.DIR_SCALE;
|
||||
|
||||
// shader handles
|
||||
private static int[] lineProgram = new int[2];
|
||||
private static int[] hLineVertexPosition = new int[2];
|
||||
private static int[] hLineColor = new int[2];
|
||||
private static int[] hLineMatrix = new int[2];
|
||||
private static int[] hLineScale = new int[2];
|
||||
private static int[] hLineWidth = new int[2];
|
||||
private static int[] hLineMode = new int[2];
|
||||
private static int mTexID;
|
||||
|
||||
static boolean init() {
|
||||
lineProgram[0] = GlUtils.createProgram(lineVertexShader,
|
||||
lineFragmentShader);
|
||||
if (lineProgram[0] == 0) {
|
||||
Log.e(TAG, "Could not create line program.");
|
||||
return false;
|
||||
}
|
||||
|
||||
lineProgram[1] = GlUtils.createProgram(lineVertexShader,
|
||||
lineSimpleFragmentShader);
|
||||
if (lineProgram[1] == 0) {
|
||||
Log.e(TAG, "Could not create simple line program.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
hLineMatrix[i] = glGetUniformLocation(lineProgram[i], "u_mvp");
|
||||
hLineScale[i] = glGetUniformLocation(lineProgram[i], "u_wscale");
|
||||
hLineWidth[i] = glGetUniformLocation(lineProgram[i], "u_width");
|
||||
hLineColor[i] = glGetUniformLocation(lineProgram[i], "u_color");
|
||||
hLineMode[i] = glGetUniformLocation(lineProgram[i], "u_mode");
|
||||
hLineVertexPosition[i] = glGetAttribLocation(lineProgram[i], "a_pos");
|
||||
}
|
||||
|
||||
// create lookup table as texture for 'length(0..1,0..1)'
|
||||
// using mirrored wrap mode for 'length(-1..1,-1..1)'
|
||||
byte[] pixel = new byte[128 * 128];
|
||||
|
||||
for (int x = 0; x < 128; x++) {
|
||||
float xx = x * x;
|
||||
for (int y = 0; y < 128; y++) {
|
||||
float yy = y * y;
|
||||
int color = (int) (Math.sqrt(xx + yy) * 2);
|
||||
if (color > 255)
|
||||
color = 255;
|
||||
pixel[x + y * 128] = (byte) color;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static void beginLines() {
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexID);
|
||||
}
|
||||
|
||||
public static void endLines() {
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
public static Layer draw(Layers layers, Layer curLayer, MapPosition pos,
|
||||
Matrices m, float div, int mode) {
|
||||
|
||||
if (curLayer == null)
|
||||
return null;
|
||||
|
||||
GLState.blend(true);
|
||||
|
||||
GLState.useProgram(lineProgram[mode]);
|
||||
|
||||
int uLineScale = hLineScale[mode];
|
||||
int uLineMode = hLineMode[mode];
|
||||
int uLineColor = hLineColor[mode];
|
||||
int uLineWidth = hLineWidth[mode];
|
||||
|
||||
GLState.enableVertexArrays(hLineVertexPosition[mode], -1);
|
||||
|
||||
glVertexAttribPointer(hLineVertexPosition[mode], 4, GL_SHORT,
|
||||
false, 0, layers.lineOffset + LINE_VERTICES_DATA_POS_OFFSET);
|
||||
|
||||
//glUniformMatrix4fv(hLineMatrix[mode], 1, false, matrix, 0);
|
||||
m.mvp.setAsUniform(hLineMatrix[mode]);
|
||||
|
||||
//int zoom = FastMath.log2((int) pos.absScale);
|
||||
int zoom = pos.zoomLevel;
|
||||
|
||||
double scale = pos.getZoomScale();
|
||||
|
||||
// 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
|
||||
double s = scale / div;
|
||||
float lineScale = (float) Math.sqrt(s * 2 / 2.2);
|
||||
|
||||
// scale factor to map one pixel on tile to one pixel on screen:
|
||||
// only works with orthographic projection
|
||||
float pixel = 0;
|
||||
|
||||
if (mode == 1)
|
||||
pixel = (float) (1.5 / s);
|
||||
|
||||
glUniform1f(uLineScale, pixel);
|
||||
int lineMode = 0;
|
||||
glUniform1f(uLineMode, lineMode);
|
||||
|
||||
boolean blur = false;
|
||||
|
||||
Layer l = curLayer;
|
||||
for (; l != null && l.type == Layer.LINE; l = l.next) {
|
||||
LineLayer ll = (LineLayer) l;
|
||||
Line line = ll.line;
|
||||
float width;
|
||||
|
||||
if (line.fade < zoom) {
|
||||
GlUtils.setColor(uLineColor, line.color, 1);
|
||||
} else if (line.fade > zoom) {
|
||||
continue;
|
||||
} else {
|
||||
float alpha = (float) (scale > 1.2 ? scale : 1.2) - 1;
|
||||
GlUtils.setColor(uLineColor, line.color, alpha);
|
||||
}
|
||||
|
||||
if (mode == 0 && blur && line.blur == 0) {
|
||||
glUniform1f(uLineScale, 0);
|
||||
blur = false;
|
||||
}
|
||||
|
||||
if (line.outline) {
|
||||
// draw linelayers references by this outline
|
||||
for (LineLayer o = ll.outlines; o != null; o = o.outlines) {
|
||||
|
||||
if (o.line.fixed /* || strokeMaxZoom */) {
|
||||
width = (float) ((ll.width + o.width) / s);
|
||||
} else {
|
||||
width = (float) (ll.width / s + o.width / lineScale);
|
||||
|
||||
// check min-size for outline
|
||||
if (o.line.min > 0 && o.width * lineScale < o.line.min * 2)
|
||||
continue;
|
||||
}
|
||||
|
||||
glUniform1f(uLineWidth, width * COORD_SCALE_BY_DIR_SCALE);
|
||||
|
||||
if (line.blur != 0) {
|
||||
glUniform1f(uLineScale, (float) (1 - (line.blur / s)));
|
||||
blur = true;
|
||||
} else if (mode == 1) {
|
||||
glUniform1f(uLineScale, pixel / width);
|
||||
}
|
||||
|
||||
if (o.roundCap) {
|
||||
if (lineMode != 1) {
|
||||
lineMode = 1;
|
||||
glUniform1f(uLineMode, lineMode);
|
||||
}
|
||||
} else if (lineMode != 0) {
|
||||
lineMode = 0;
|
||||
glUniform1f(uLineMode, lineMode);
|
||||
}
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, o.offset, o.verticesCnt);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (line.fixed /* || strokeMaxZoom */) {
|
||||
// invert scaling of extrusion vectors so that line
|
||||
// width stays the same.
|
||||
width = (float) (ll.width / s);
|
||||
} else {
|
||||
// reduce linear scaling of extrusion vectors so that
|
||||
// line width increases by sqrt(2.2).
|
||||
width = ll.width / lineScale;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
glUniform1f(uLineWidth, width * COORD_SCALE_BY_DIR_SCALE);
|
||||
|
||||
if (line.blur != 0) {
|
||||
glUniform1f(uLineScale, line.blur);
|
||||
blur = true;
|
||||
} else if (mode == 1) {
|
||||
glUniform1f(uLineScale, pixel / width);
|
||||
}
|
||||
|
||||
if (ll.roundCap) {
|
||||
if (lineMode != 1) {
|
||||
lineMode = 1;
|
||||
glUniform1f(uLineMode, lineMode);
|
||||
}
|
||||
} else if (lineMode != 0) {
|
||||
lineMode = 0;
|
||||
glUniform1f(uLineMode, lineMode);
|
||||
}
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, l.offset, l.verticesCnt);
|
||||
}
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
private final static String lineVertexShader = ""
|
||||
+ "precision mediump float;"
|
||||
+ "uniform mat4 u_mvp;"
|
||||
// factor to increase line width relative to scale
|
||||
+ "uniform float u_width;"
|
||||
// xy hold position, zw extrusion vector
|
||||
+ "attribute vec4 a_pos;"
|
||||
+ "uniform float u_mode;"
|
||||
+ "varying vec2 v_st;"
|
||||
+ "void main() {"
|
||||
// scale extrusion to u_width pixel
|
||||
// just ignore the two most insignificant bits of a_st :)
|
||||
+ " vec2 dir = a_pos.zw;"
|
||||
+ " gl_Position = u_mvp * vec4(a_pos.xy + (u_width * dir), 0.0, 1.0);"
|
||||
// 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;"
|
||||
+ "}";
|
||||
|
||||
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;"
|
||||
+ "void main() {"
|
||||
//+ " float len;"
|
||||
// (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;"
|
||||
// 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);"
|
||||
//+ " gl_FragColor = mix(vec4(1.0,0.0,0.0,1.0), u_color, smoothstep(0.0, u_wscale, 1.0 - len));"
|
||||
+ " gl_FragColor = u_color * min(1.0, (1.0 - len) / u_wscale);"
|
||||
+ "}";
|
||||
|
||||
private final static String lineFragmentShader = ""
|
||||
+ "#extension GL_OES_standard_derivatives : enable\n"
|
||||
+ "precision mediump float;"
|
||||
+ "uniform sampler2D tex;"
|
||||
+ "uniform float u_mode;"
|
||||
+ "uniform vec4 u_color;"
|
||||
+ "uniform float u_wscale;"
|
||||
+ "varying vec2 v_st;"
|
||||
+ "void main() {"
|
||||
+ " float len;"
|
||||
+ " float fuzz;"
|
||||
+ " if (u_mode == 0.0){"
|
||||
+ " len = abs(v_st.s);"
|
||||
+ " fuzz = fwidth(v_st.s);"
|
||||
+ " } else {"
|
||||
+ " len = texture2D(tex, v_st).a;"
|
||||
//+ " len = length(v_st);"
|
||||
+ " vec2 st_width = fwidth(v_st);"
|
||||
+ " fuzz = max(st_width.s, st_width.t);"
|
||||
+ " }"
|
||||
//+ " gl_FragColor = u_color * smoothstep(0.0, fuzz + u_wscale, 1.0 - len);"
|
||||
// smoothstep is too sharp, guess one could increase extrusion with z..
|
||||
// this looks ok:
|
||||
//+ " gl_FragColor = u_color * min(1.0, (1.0 - len) / (u_wscale + fuzz));"
|
||||
// can be faster according to nvidia docs 'Optimize OpenGL ES 2.0 Performace'
|
||||
+ " gl_FragColor = u_color * clamp((1.0 - len) / (u_wscale + fuzz), 0.0, 1.0);"
|
||||
//+ " gl_FragColor = mix(vec4(0.0,1.0,0.0,1.0), u_color, clamp((1.0 - len) / (u_wscale + fuzz), 0.0, 1.0));"
|
||||
+ "}";
|
||||
|
||||
// private final static String lineVertexShader = ""
|
||||
// + "precision mediump float;"
|
||||
// + "uniform mat4 u_mvp;"
|
||||
// + "uniform float u_width;"
|
||||
// + "attribute vec4 a_pos;"
|
||||
// + "uniform int u_mode;"
|
||||
// //+ "attribute vec2 a_st;"
|
||||
// + "varying vec2 v_st;"
|
||||
// + "const float dscale = 8.0/2048.0;"
|
||||
// + "void main() {"
|
||||
// // scale extrusion to u_width pixel
|
||||
// // just ignore the two most insignificant bits of a_st :)
|
||||
// + " vec2 dir = a_pos.zw;"
|
||||
// + " gl_Position = u_mvp * vec4(a_pos.xy + (dscale * u_width * dir), 0.0, 1.0);"
|
||||
// // last two bits of a_st hold the texture coordinates
|
||||
// + " v_st = u_width * (abs(mod(dir, 4.0)) - 1.0);"
|
||||
// // use bit operations when available (gles 1.3)
|
||||
// // + " v_st = u_width * vec2(a_st.x & 3 - 1, a_st.y & 3 - 1);"
|
||||
// + "}";
|
||||
//
|
||||
// private final static String lineSimpleFragmentShader = ""
|
||||
// + "precision mediump float;"
|
||||
// + "uniform float u_wscale;"
|
||||
// + "uniform float u_width;"
|
||||
// + "uniform int u_mode;"
|
||||
// + "uniform vec4 u_color;"
|
||||
// + "varying vec2 v_st;"
|
||||
// + "void main() {"
|
||||
// + " float len;"
|
||||
// + " if (u_mode == 0)"
|
||||
// + " len = abs(v_st.s);"
|
||||
// + " else "
|
||||
// + " len = length(v_st);"
|
||||
// // fade to alpha. u_wscale is the width in pixel which should be
|
||||
// // faded, u_width - len the position of this fragment on the
|
||||
// // perpendicular to this line segment. this only works with no
|
||||
// // perspective
|
||||
// //+ " gl_FragColor = min(1.0, (u_width - len) / u_wscale) * u_color;"
|
||||
// + " gl_FragColor = u_color * smoothstep(0.0, u_wscale, (u_width - len));"
|
||||
// + "}";
|
||||
//
|
||||
// private final static String lineFragmentShader = ""
|
||||
// + "#extension GL_OES_standard_derivatives : enable\n"
|
||||
// + "precision mediump float;"
|
||||
// + "uniform float u_wscale;"
|
||||
// + "uniform float u_width;"
|
||||
// + "uniform int u_mode;"
|
||||
// + "uniform vec4 u_color;"
|
||||
// + "varying vec2 v_st;"
|
||||
// + "void main() {"
|
||||
// + " float len;"
|
||||
// + " float fuzz;"
|
||||
// + " if (u_mode == 0){"
|
||||
// + " len = abs(v_st.s);"
|
||||
// + " fuzz = u_wscale + fwidth(v_st.s);"
|
||||
// + " } else {"
|
||||
// + " len = length(v_st);"
|
||||
// + " vec2 st_width = fwidth(v_st);"
|
||||
// + " fuzz = u_wscale + max(st_width.s, st_width.t);"
|
||||
// + " }"
|
||||
// + " gl_FragColor = u_color * min(1.0, (u_width - len) / fuzz);"
|
||||
// + "}";
|
||||
}
|
||||
236
src/org/oscim/renderer/sublayers/LineTexLayer.java
Normal file
236
src/org/oscim/renderer/sublayers/LineTexLayer.java
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* 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.sublayers;
|
||||
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import org.oscim.renderer.GLRenderer;
|
||||
import org.oscim.theme.renderinstruction.Line;
|
||||
|
||||
/**
|
||||
* Layer for textured or stippled lines
|
||||
*
|
||||
* this would be all so much simpler with geometry shaders...
|
||||
*/
|
||||
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,
|
||||
//
|
||||
// BIG NOTE: renderer assumes to be able to offset vertex array position
|
||||
// so that in the first pass 'pos1' offset will be < 0 if no data precedes
|
||||
// - in our case there is always the polygon fill array at start
|
||||
// - see addLine hack otherwise.
|
||||
|
||||
private static final float COORD_SCALE = GLRenderer.COORD_SCALE;
|
||||
// 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 (vertexItems == null) {
|
||||
curItem = vertexItems = VertexItem.pool.get();
|
||||
|
||||
// HACK add one vertex offset when compiling
|
||||
// buffer otherwise one cant use the full
|
||||
// VertexItem (see Layers.compile)
|
||||
// add the two 'x' at front and end
|
||||
//verticesCnt = 2;
|
||||
|
||||
// the additional end vertex to make sure
|
||||
// not to read outside allocated memory
|
||||
verticesCnt = 1;
|
||||
}
|
||||
|
||||
VertexItem 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 == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.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;
|
||||
}
|
||||
|
||||
evenSegment = even;
|
||||
|
||||
// advance offset to last written position
|
||||
if (!even)
|
||||
opos += 12;
|
||||
|
||||
si.used = opos;
|
||||
curItem = si;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clear() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void compile(ShortBuffer sbuf) {
|
||||
}
|
||||
|
||||
}
|
||||
321
src/org/oscim/renderer/sublayers/LineTexRenderer.java
Normal file
321
src/org/oscim/renderer/sublayers/LineTexRenderer.java
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* 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.sublayers;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.renderer.GLRenderer;
|
||||
import org.oscim.renderer.GLState;
|
||||
import org.oscim.renderer.GLRenderer.Matrices;
|
||||
import org.oscim.theme.renderinstruction.Line;
|
||||
import org.oscim.utils.GlUtils;
|
||||
|
||||
import android.opengl.GLES20;
|
||||
import android.util.Log;
|
||||
|
||||
public class LineTexRenderer {
|
||||
private final static String TAG = LineTexRenderer.class.getName();
|
||||
|
||||
// factor to normalize extrusion vector and scale to coord scale
|
||||
private final static float COORD_SCALE_BY_DIR_SCALE =
|
||||
GLRenderer.COORD_SCALE / LineLayer.DIR_SCALE;
|
||||
|
||||
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 hWidth;
|
||||
private static int hPatternScale;
|
||||
private static int hPatternWidth;
|
||||
|
||||
private static int mVertexFlipID;
|
||||
|
||||
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");
|
||||
hWidth = GLES20.glGetUniformLocation(shader, "u_width");
|
||||
hPatternScale = GLES20.glGetUniformLocation(shader, "u_pscale");
|
||||
hPatternWidth = GLES20.glGetUniformLocation(shader, "u_pwidth");
|
||||
|
||||
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[] vboIds = new int[1];
|
||||
GLES20.glGenBuffers(1, vboIds, 0);
|
||||
mVertexFlipID = vboIds[0];
|
||||
|
||||
// 0, 1, 0, 1, 0, ...
|
||||
byte[] flip = new byte[GLRenderer.maxQuads * 4];
|
||||
for (int i = 0; i < flip.length; i++)
|
||||
flip[i] = (byte) (i % 2);
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(flip.length)
|
||||
.order(ByteOrder.nativeOrder());
|
||||
|
||||
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);
|
||||
|
||||
|
||||
// mTexID = new int[10];
|
||||
// byte[] stipple = new byte[2];
|
||||
// stipple[0] = 32;
|
||||
// stipple[1] = 32;
|
||||
// mTexID[0] = 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, Matrices m, 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);
|
||||
|
||||
m.mvp.setAsUniform(hMatrix);
|
||||
|
||||
int maxIndices = GLRenderer.maxQuads * 6;
|
||||
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,
|
||||
GLRenderer.mQuadIndicesID);
|
||||
|
||||
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);
|
||||
|
||||
float scale = (float)pos.getZoomScale();
|
||||
|
||||
float s = scale / div;
|
||||
|
||||
//GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexID[0]);
|
||||
|
||||
Layer l = curLayer;
|
||||
for (;l != null && l.type == Layer.TEXLINE; l = l.next) {
|
||||
LineTexLayer ll = (LineTexLayer) l;
|
||||
Line line = ll.line;
|
||||
|
||||
GlUtils.setColor(hTexColor, line.stippleColor, 1);
|
||||
GlUtils.setColor(hBgColor, line.color, 1);
|
||||
|
||||
float pScale = (int) (s+0.5f);
|
||||
if (pScale < 1)
|
||||
pScale = 1;
|
||||
|
||||
GLES20.glUniform1f(hPatternScale, (GLRenderer.COORD_SCALE * line.stipple) / pScale);
|
||||
GLES20.glUniform1f(hPatternWidth, line.stippleWidth);
|
||||
|
||||
GLES20.glUniform1f(hScale, scale);
|
||||
// keep line width fixed
|
||||
GLES20.glUniform1f(hWidth, ll.width / s * COORD_SCALE_BY_DIR_SCALE);
|
||||
|
||||
// add offset vertex
|
||||
int vOffset = -STRIDE;
|
||||
|
||||
// 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 = (l.offset + i * 8) + vOffset;
|
||||
|
||||
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 = (l.offset + i * 8) + vOffset;
|
||||
|
||||
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);
|
||||
}
|
||||
//GlUtils.checkGlError(TAG);
|
||||
}
|
||||
|
||||
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
GLES20.glDisableVertexAttribArray(hVertexPosition0);
|
||||
GLES20.glDisableVertexAttribArray(hVertexPosition1);
|
||||
GLES20.glDisableVertexAttribArray(hVertexLength0);
|
||||
GLES20.glDisableVertexAttribArray(hVertexLength1);
|
||||
GLES20.glDisableVertexAttribArray(hVertexFlip);
|
||||
|
||||
//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_pscale;"
|
||||
+ "uniform float u_width;"
|
||||
+ "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() {"
|
||||
+ " vec4 pos;"
|
||||
+ " if (a_flip == 0.0){"
|
||||
+ " vec2 dir = u_width * a_pos0.zw;"
|
||||
+ " pos = vec4(a_pos0.xy + dir, 0.0, 1.0);"
|
||||
+ " v_st = vec2(a_len0.x / u_pscale, 1.0);"
|
||||
+ " } else {"
|
||||
+ " vec2 dir = u_width * a_pos1.zw ;"
|
||||
+ " pos = vec4(a_pos1.xy - dir, 0.0, 1.0);"
|
||||
+ " v_st = vec2(a_len1.x / u_pscale, -1.0);"
|
||||
+ " }"
|
||||
+ " gl_Position = u_mvp * pos;"
|
||||
+ "}";
|
||||
|
||||
//*
|
||||
final static String fragmentShader = ""
|
||||
+ "#extension GL_OES_standard_derivatives : enable\n"
|
||||
+ " precision mediump float;"
|
||||
+ " uniform vec4 u_color;"
|
||||
+ " uniform vec4 u_bgcolor;"
|
||||
+ " uniform float u_pwidth;"
|
||||
+ " varying vec2 v_st;"
|
||||
+ " void main() {"
|
||||
// distance on perpendicular to the line
|
||||
+ " float dist = abs(v_st.t);"
|
||||
+ " float fuzz = fwidth(v_st.t);"
|
||||
+ " float fuzz_p = fwidth(v_st.s);"
|
||||
+ " float line_w = smoothstep(0.0, fuzz, 1.0 - dist);"
|
||||
+ " float stipple_w = smoothstep(0.0, fuzz, u_pwidth - dist);"
|
||||
// triangle waveform in the range 0..1 for regular pattern
|
||||
+ " float phase = abs(mod(v_st.s, 2.0) - 1.0);"
|
||||
// interpolate between on/off phase, 0.5 = equal phase length
|
||||
+ " float stipple_p = smoothstep(0.5 - fuzz_p, 0.5 + fuzz_p, phase);"
|
||||
+ " gl_FragColor = line_w * mix(u_bgcolor, u_color, min(stipple_w, stipple_p));"
|
||||
+ " } "; //*/
|
||||
|
||||
/*
|
||||
final static String fragmentShader = ""
|
||||
+ "#extension GL_OES_standard_derivatives : enable\n"
|
||||
+ " precision mediump float;"
|
||||
+ " uniform sampler2D tex;"
|
||||
+ " uniform float u_scale;"
|
||||
+ " 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 fuzz = fwidth(v_st.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 = 1.0 - smoothstep(1.0 - fuzz, 1.0, length(vec2(len*u_scale, v_st.t)));"
|
||||
+ " gl_FragColor = u_bgcolor * stipple_p;"
|
||||
// + " gl_FragColor = line_w * mix(u_bgcolor, u_color, min(stipple_w, stipple_p));"
|
||||
+ "}"; //*/
|
||||
/*
|
||||
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;"
|
||||
+ " uniform float u_pwidth;"
|
||||
+ " varying vec2 v_st;"
|
||||
+ " void main() {"
|
||||
+ " float dist = 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(u_pwidth - fuzz, u_pwidth, tex_w));"
|
||||
+ " float stipple_p = smoothstep(0.495, 0.505, dist);"
|
||||
+ " gl_FragColor = line_w * mix(u_bgcolor, u_color, min(stipple_w, stipple_p));"
|
||||
+ " } "; //*/
|
||||
|
||||
}
|
||||
40
src/org/oscim/renderer/sublayers/MeshLayer.java
Normal file
40
src/org/oscim/renderer/sublayers/MeshLayer.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.sublayers;
|
||||
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import org.oscim.core.GeometryBuffer;
|
||||
|
||||
public class MeshLayer extends Layer {
|
||||
|
||||
public void addMesh(GeometryBuffer geom){
|
||||
|
||||
for (int i = 0, n = geom.points.length; i < n; i++){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void compile(ShortBuffer sbuf) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clear() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
19
src/org/oscim/renderer/sublayers/MeshRenderer.java
Normal file
19
src/org/oscim/renderer/sublayers/MeshRenderer.java
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.sublayers;
|
||||
|
||||
public class MeshRenderer {
|
||||
|
||||
}
|
||||
99
src/org/oscim/renderer/sublayers/PolygonLayer.java
Normal file
99
src/org/oscim/renderer/sublayers/PolygonLayer.java
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2012 Hannes Janetzek
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.renderer.sublayers;
|
||||
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.renderer.GLRenderer;
|
||||
import org.oscim.theme.renderinstruction.Area;
|
||||
|
||||
public final class PolygonLayer extends Layer {
|
||||
private static final float S = GLRenderer.COORD_SCALE;
|
||||
|
||||
public Area area;
|
||||
|
||||
PolygonLayer(int layer) {
|
||||
this.level = layer;
|
||||
this.type = Layer.POLYGON;
|
||||
curItem = VertexItem.pool.get();
|
||||
vertexItems = curItem;
|
||||
}
|
||||
|
||||
public void addPolygon(float[] points, short[] index) {
|
||||
short center = (short) ((Tile.SIZE >> 1) * S);
|
||||
|
||||
VertexItem si = curItem;
|
||||
short[] v = si.vertices;
|
||||
int outPos = si.used;
|
||||
|
||||
for (int i = 0, pos = 0, n = index.length; i < n; i++) {
|
||||
int length = index[i];
|
||||
if (length < 0)
|
||||
break;
|
||||
|
||||
// need at least three points
|
||||
if (length < 6) {
|
||||
pos += length;
|
||||
continue;
|
||||
}
|
||||
|
||||
verticesCnt += length / 2 + 2;
|
||||
|
||||
int inPos = pos;
|
||||
|
||||
if (outPos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
outPos = 0;
|
||||
}
|
||||
|
||||
v[outPos++] = center;
|
||||
v[outPos++] = center;
|
||||
|
||||
for (int j = 0; j < length; j += 2) {
|
||||
if (outPos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
outPos = 0;
|
||||
}
|
||||
v[outPos++] = (short) (points[inPos++] * S);
|
||||
v[outPos++] = (short) (points[inPos++] * S);
|
||||
}
|
||||
|
||||
if (outPos == VertexItem.SIZE) {
|
||||
si = si.next = VertexItem.pool.get();
|
||||
v = si.vertices;
|
||||
outPos = 0;
|
||||
}
|
||||
|
||||
v[outPos++] = (short) (points[pos + 0] * S);
|
||||
v[outPos++] = (short) (points[pos + 1] * S);
|
||||
|
||||
pos += length;
|
||||
}
|
||||
|
||||
si.used = outPos;
|
||||
curItem = si;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void compile(ShortBuffer sbuf) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clear() {
|
||||
}
|
||||
}
|
||||
433
src/org/oscim/renderer/sublayers/PolygonRenderer.java
Normal file
433
src/org/oscim/renderer/sublayers/PolygonRenderer.java
Normal file
@@ -0,0 +1,433 @@
|
||||
/*
|
||||
* Copyright 2012 Hannes Janetzek
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.renderer.sublayers;
|
||||
|
||||
import static android.opengl.GLES20.GL_ALWAYS;
|
||||
import static android.opengl.GLES20.GL_EQUAL;
|
||||
import static android.opengl.GLES20.GL_INVERT;
|
||||
import static android.opengl.GLES20.GL_SHORT;
|
||||
import static android.opengl.GLES20.GL_TRIANGLE_FAN;
|
||||
import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
|
||||
import static android.opengl.GLES20.glColorMask;
|
||||
import static android.opengl.GLES20.glDepthMask;
|
||||
import static android.opengl.GLES20.glDrawArrays;
|
||||
import static android.opengl.GLES20.glGetAttribLocation;
|
||||
import static android.opengl.GLES20.glGetUniformLocation;
|
||||
import static android.opengl.GLES20.glStencilFunc;
|
||||
import static android.opengl.GLES20.glStencilMask;
|
||||
import static android.opengl.GLES20.glStencilOp;
|
||||
import static android.opengl.GLES20.glUniform4fv;
|
||||
import static android.opengl.GLES20.glVertexAttribPointer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.renderer.GLRenderer;
|
||||
import org.oscim.renderer.GLState;
|
||||
import org.oscim.renderer.GLRenderer.Matrices;
|
||||
import org.oscim.theme.renderinstruction.Area;
|
||||
import org.oscim.utils.GlUtils;
|
||||
import org.oscim.utils.Matrix4;
|
||||
|
||||
import android.opengl.GLES20;
|
||||
|
||||
public final class PolygonRenderer {
|
||||
//private static final String TAG = PolygonRenderer.class.getName();
|
||||
|
||||
private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0;
|
||||
private static final int STENCIL_BITS = 8;
|
||||
private final static int CLIP_BIT = 0x80;
|
||||
|
||||
private static final float FADE_START = 1.3f;
|
||||
|
||||
private static PolygonLayer[] mFillPolys;
|
||||
|
||||
private static int polygonProgram;
|
||||
private static int hPolygonVertexPosition;
|
||||
private static int hPolygonMatrix;
|
||||
private static int hPolygonColor;
|
||||
|
||||
static boolean init() {
|
||||
|
||||
// Set up the program for rendering polygons
|
||||
if (GLRenderer.debugView) {
|
||||
polygonProgram = GlUtils.createProgram(polygonVertexShaderZ,
|
||||
polygonFragmentShaderZ);
|
||||
} else {
|
||||
polygonProgram = GlUtils.createProgram(polygonVertexShader,
|
||||
polygonFragmentShader);
|
||||
}
|
||||
if (polygonProgram == 0) {
|
||||
// Log.e(TAG, "Could not create polygon program.");
|
||||
return false;
|
||||
}
|
||||
hPolygonMatrix = glGetUniformLocation(polygonProgram, "u_mvp");
|
||||
hPolygonColor = glGetUniformLocation(polygonProgram, "u_color");
|
||||
hPolygonVertexPosition = glGetAttribLocation(polygonProgram, "a_pos");
|
||||
|
||||
mFillPolys = new PolygonLayer[STENCIL_BITS];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void fillPolygons(int start, int end, int zoom, float scale) {
|
||||
|
||||
/* draw to framebuffer */
|
||||
glColorMask(true, true, true, true);
|
||||
|
||||
/* do not modify stencil buffer */
|
||||
glStencilMask(0x00);
|
||||
|
||||
for (int c = start; c < end; c++) {
|
||||
Area a = mFillPolys[c].area;
|
||||
|
||||
if (a.fade >= zoom) {
|
||||
float f = 1.0f;
|
||||
/* fade in/out */
|
||||
if (a.fade >= zoom) {
|
||||
if (scale > FADE_START)
|
||||
f = scale - 1;
|
||||
else
|
||||
f = FADE_START - 1;
|
||||
}
|
||||
GLState.blend(true);
|
||||
|
||||
GlUtils.setColor(hPolygonColor, a.color, f);
|
||||
|
||||
} else if (a.blend > 0 && a.blend <= zoom) {
|
||||
/* blend colors (not alpha) */
|
||||
GLState.blend(false);
|
||||
|
||||
if (a.blend == zoom)
|
||||
GlUtils.setColorBlend(hPolygonColor,
|
||||
a.color, a.blendColor, scale - 1.0f);
|
||||
else
|
||||
GlUtils.setColor(hPolygonColor, a.blendColor, 1);
|
||||
|
||||
} else {
|
||||
if (a.color < 0xff000000)
|
||||
GLState.blend(true);
|
||||
else
|
||||
GLState.blend(false);
|
||||
|
||||
GlUtils.setColor(hPolygonColor, a.color, 1);
|
||||
}
|
||||
|
||||
// set stencil buffer mask used to draw this layer
|
||||
// also check that clip bit is set to avoid overdraw
|
||||
// of other tiles
|
||||
glStencilFunc(GL_EQUAL, 0xff, CLIP_BIT | 1 << c);
|
||||
|
||||
/* draw tile fill coordinates */
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// current layer to fill (0 - STENCIL_BITS-1)
|
||||
private static int mCount;
|
||||
|
||||
/**
|
||||
* draw polygon layers (unil layer.next is not polygon layer)
|
||||
* using stencil buffer method
|
||||
*
|
||||
* @param pos
|
||||
* used to fade layers accorind to 'fade'
|
||||
* in layer.area.
|
||||
* @param layer
|
||||
* layer to draw (referencing vertices in current vbo)
|
||||
* @param m
|
||||
* current Matrices
|
||||
* @param first
|
||||
* pass true to clear stencil buffer region
|
||||
* @param clip
|
||||
* clip to first quad in current vbo
|
||||
* @return
|
||||
* next layer
|
||||
*/
|
||||
public static Layer draw(MapPosition pos, Layer layer,
|
||||
Matrices m, boolean first, boolean clip) {
|
||||
|
||||
GLState.test(false, true);
|
||||
|
||||
GLState.useProgram(polygonProgram);
|
||||
GLState.enableVertexArrays(hPolygonVertexPosition, -1);
|
||||
glVertexAttribPointer(hPolygonVertexPosition, 2, GL_SHORT,
|
||||
false, 0, POLYGON_VERTICES_DATA_POS_OFFSET);
|
||||
|
||||
m.mvp.setAsUniform(hPolygonMatrix);
|
||||
|
||||
int zoom = pos.zoomLevel;
|
||||
int cur = mCount;
|
||||
|
||||
// reset start when only one layer left in stencil buffer
|
||||
if (first || cur > 5)
|
||||
cur = 0;
|
||||
|
||||
int start = cur;
|
||||
|
||||
float scale = (float)pos.getZoomScale();
|
||||
|
||||
Layer l = layer;
|
||||
for (; l != null && l.type == Layer.POLYGON; l = l.next) {
|
||||
PolygonLayer pl = (PolygonLayer) l;
|
||||
|
||||
// fade out polygon layers (set in RenderTheme)
|
||||
if (pl.area.fade > 0 && pl.area.fade > zoom)
|
||||
continue;
|
||||
|
||||
if (cur == start) {
|
||||
drawStencilRegion(first);
|
||||
first = false;
|
||||
|
||||
// op for stencil method polygon drawing
|
||||
glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GL_INVERT);
|
||||
}
|
||||
|
||||
mFillPolys[cur] = pl;
|
||||
|
||||
// set stencil mask to draw to
|
||||
glStencilMask(1 << cur++);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_FAN, l.offset, l.verticesCnt);
|
||||
|
||||
// draw up to 7 layers into stencil buffer
|
||||
if (cur == STENCIL_BITS - 1) {
|
||||
fillPolygons(start, cur, zoom, scale);
|
||||
start = cur = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (cur > 0)
|
||||
fillPolygons(start, cur, zoom, scale);
|
||||
|
||||
if (clip) {
|
||||
if (first) {
|
||||
drawStencilRegion(first);
|
||||
// disable writes to stencil buffer
|
||||
glStencilMask(0x00);
|
||||
// enable writes to color buffer
|
||||
glColorMask(true, true, true, true);
|
||||
} else {
|
||||
// set test for clip to tile region
|
||||
glStencilFunc(GL_EQUAL, CLIP_BIT, CLIP_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
mCount = cur;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a tile filling rectangle to set stencil- and depth buffer
|
||||
* appropriately
|
||||
*
|
||||
* @param first in the first run the clip region is set based on
|
||||
* depth buffer and depth buffer is updated
|
||||
*/
|
||||
static void drawStencilRegion(boolean first) {
|
||||
|
||||
// if (!first) {
|
||||
// glStencilMask(0x7F);
|
||||
// GLES20.glClear(GLES20.GL_STENCIL_BUFFER_BIT);
|
||||
// // disable drawing to color buffer
|
||||
// glColorMask(false, false, false, false);
|
||||
// glStencilFunc(GL_EQUAL, CLIP_BIT, CLIP_BIT);
|
||||
// }
|
||||
|
||||
// disable drawing to color buffer
|
||||
glColorMask(false, false, false, false);
|
||||
|
||||
// write to all stencil bits
|
||||
glStencilMask(0xFF);
|
||||
|
||||
if (first) {
|
||||
// clear previous clip-region from stencil buffer
|
||||
//GLES20.glClear(GLES20.GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
// Draw clip-region into depth and stencil buffer
|
||||
// this is used for tile line and polygon layers.
|
||||
// Depth offset is increased for each tile. Together
|
||||
// with depth test (GL_LESS) this ensures to only
|
||||
// draw where no other tile has drawn yet.
|
||||
GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
// test GL_LESS and write to depth buffer
|
||||
GLState.test(true, true);
|
||||
glDepthMask(true);
|
||||
|
||||
// always pass stencil test and set clip bit
|
||||
glStencilFunc(GL_ALWAYS, CLIP_BIT, 0x00);
|
||||
} else {
|
||||
// use clip bit from stencil buffer
|
||||
// to clear stencil 'layer-bits' (0x7f)
|
||||
glStencilFunc(GL_EQUAL, CLIP_BIT, CLIP_BIT);
|
||||
}
|
||||
|
||||
// set clip bit (0x80) for draw region
|
||||
glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_REPLACE);
|
||||
|
||||
// draw a quad for the tile region
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
if (first) {
|
||||
// dont modify depth buffer
|
||||
glDepthMask(false);
|
||||
// test only stencil
|
||||
GLState.test(false, true);
|
||||
|
||||
GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
glStencilFunc(GL_EQUAL, CLIP_BIT, CLIP_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawOver(Matrices m, boolean drawColor, int color) {
|
||||
if (GLState.useProgram(polygonProgram)) {
|
||||
|
||||
GLState.enableVertexArrays(hPolygonVertexPosition, -1);
|
||||
|
||||
glVertexAttribPointer(hPolygonVertexPosition, 2, GL_SHORT,
|
||||
false, 0, POLYGON_VERTICES_DATA_POS_OFFSET);
|
||||
|
||||
m.mvp.setAsUniform(hPolygonMatrix);
|
||||
}
|
||||
|
||||
/*
|
||||
* clear stencilbuffer (tile region) by drawing
|
||||
* a quad with func 'always' and op 'zero'
|
||||
*/
|
||||
|
||||
if (drawColor) {
|
||||
GlUtils.setColor(hPolygonColor, color, 1);
|
||||
GLState.blend(true);
|
||||
} else {
|
||||
// disable drawing to framebuffer (will be re-enabled in fill)
|
||||
glColorMask(false, false, false, false);
|
||||
}
|
||||
// always pass stencil test:
|
||||
//glStencilFunc(GL_ALWAYS, 0x00, 0x00);
|
||||
glStencilFunc(GL_EQUAL, CLIP_BIT, CLIP_BIT);
|
||||
|
||||
// write to all bits
|
||||
glStencilMask(0xFF);
|
||||
// zero out area to draw to
|
||||
glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_ZERO);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
if (!drawColor)
|
||||
glColorMask(true, true, true, true);
|
||||
}
|
||||
|
||||
private static float[] debugFillColor = { 0.3f, 0.0f, 0.0f, 0.3f };
|
||||
private static float[] debugFillColor2 = { .8f, .8f, .8f, .8f };
|
||||
private static FloatBuffer mDebugFill;
|
||||
|
||||
static void debugDraw(Matrix4 m, float[] coords, int color) {
|
||||
GLState.test(false, false);
|
||||
if (mDebugFill == null)
|
||||
mDebugFill = ByteBuffer.allocateDirect(32).order(ByteOrder.nativeOrder())
|
||||
.asFloatBuffer();
|
||||
|
||||
mDebugFill.put(coords);
|
||||
|
||||
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
|
||||
|
||||
mDebugFill.position(0);
|
||||
GLState.useProgram(polygonProgram);
|
||||
GLES20.glEnableVertexAttribArray(hPolygonVertexPosition);
|
||||
|
||||
glVertexAttribPointer(hPolygonVertexPosition, 2, GLES20.GL_FLOAT,
|
||||
false, 0, mDebugFill);
|
||||
|
||||
m.setAsUniform(hPolygonMatrix);
|
||||
|
||||
if (color == 0)
|
||||
glUniform4fv(hPolygonColor, 1, debugFillColor, 0);
|
||||
else
|
||||
glUniform4fv(hPolygonColor, 1, debugFillColor2, 0);
|
||||
|
||||
glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
GlUtils.checkGlError("draw debug");
|
||||
}
|
||||
|
||||
private final static String polygonVertexShader = ""
|
||||
+ "precision mediump float;"
|
||||
+ "uniform mat4 u_mvp;"
|
||||
+ "attribute vec4 a_pos;"
|
||||
+ "void main() {"
|
||||
+ " gl_Position = u_mvp * a_pos;"
|
||||
+ "}";
|
||||
|
||||
private final static String polygonFragmentShader = ""
|
||||
+ "precision mediump float;"
|
||||
+ "uniform vec4 u_color;"
|
||||
+ "void main() {"
|
||||
+ " gl_FragColor = u_color;"
|
||||
+ "}";
|
||||
|
||||
private final static String polygonVertexShaderZ = ""
|
||||
+ "precision highp float;"
|
||||
+ "uniform mat4 u_mvp;"
|
||||
+ "attribute vec4 a_pos;"
|
||||
+ "varying float z;"
|
||||
+ "void main() {"
|
||||
+ " gl_Position = u_mvp * a_pos;"
|
||||
+ " z = gl_Position.z;"
|
||||
+ "}";
|
||||
private final static String polygonFragmentShaderZ = ""
|
||||
+ "precision highp float;"
|
||||
+ "uniform vec4 u_color;"
|
||||
+ "varying float z;"
|
||||
+ "void main() {"
|
||||
+ "if (z < -1.0)"
|
||||
+ " gl_FragColor = vec4(0.0, z + 2.0, 0.0, 1.0)*0.8;"
|
||||
+ "else if (z < 0.0)"
|
||||
+ " gl_FragColor = vec4(z + 1.0, 0.0, 0.0, 1.0)*0.8;"
|
||||
+ "else if (z < 1.0)"
|
||||
+ " gl_FragColor = vec4(0.0, 0.0, z, 1.0)*0.8;"
|
||||
+ "else"
|
||||
+ " gl_FragColor = vec4(0.0, z - 1.0, 0.0, 1.0)*0.8;"
|
||||
+ "}";
|
||||
|
||||
// private final static String polygonTexVertexShader = ""
|
||||
// + "precision mediump float;"
|
||||
// + "uniform mat4 u_mvp;"
|
||||
// + "attribute vec4 a_pos;"
|
||||
// + "varying vec2 v_st;"
|
||||
// + "void main() {"
|
||||
// + " if(gl_VertexID == 0)"
|
||||
// + " v_st = vec2(0.0,0.0);"
|
||||
// + " else if(gl_VertexID == 1)"
|
||||
// + " v_st = vec2(1.0,0.0);"
|
||||
// + " else if(gl_VertexID == 2)"
|
||||
// + " v_st = vec2(1.0,1.0);"
|
||||
// + " else if(gl_VertexID == 3)"
|
||||
// + " v_st = vec2(0.0,1.0);"
|
||||
// + " gl_Position = u_mvp * a_pos;"
|
||||
// + "}";
|
||||
// private final static String polygonTexFragmentShader = ""
|
||||
// + "precision mediump float;"
|
||||
// + "uniform vec4 u_color;"
|
||||
// + "uniform sampler2D tex;"
|
||||
// + "varying vec2 v_st;"
|
||||
// + "void main() {"
|
||||
// + " gl_FragColor = u_color * texture2D(tex, v_st);"
|
||||
// + "}";
|
||||
}
|
||||
49
src/org/oscim/renderer/sublayers/SymbolItem.java
Normal file
49
src/org/oscim/renderer/sublayers/SymbolItem.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2012 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.sublayers;
|
||||
|
||||
import org.oscim.utils.pool.Inlist;
|
||||
import org.oscim.utils.pool.SyncPool;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
public class SymbolItem extends Inlist<SymbolItem> {
|
||||
|
||||
public final static SyncPool<SymbolItem> pool = new SyncPool<SymbolItem>() {
|
||||
|
||||
@Override
|
||||
protected SymbolItem createItem() {
|
||||
return new SymbolItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clearItem(SymbolItem it) {
|
||||
// drop references
|
||||
it.drawable = null;
|
||||
it.bitmap = null;
|
||||
}
|
||||
};
|
||||
|
||||
public Bitmap bitmap;
|
||||
public Drawable drawable;
|
||||
public float x;
|
||||
public float y;
|
||||
public boolean billboard;
|
||||
public int state;
|
||||
|
||||
// center, top, bottom, left, right, top-left...
|
||||
// byte placement;
|
||||
}
|
||||
259
src/org/oscim/renderer/sublayers/SymbolLayer.java
Normal file
259
src/org/oscim/renderer/sublayers/SymbolLayer.java
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright 2012 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.sublayers;
|
||||
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.Log;
|
||||
|
||||
// TODO share one static texture for all poi map symabols
|
||||
|
||||
public final class SymbolLayer extends TextureLayer {
|
||||
private final static String TAG = SymbolLayer.class.getSimpleName();
|
||||
|
||||
private final static int TEXTURE_WIDTH = TextureItem.TEXTURE_WIDTH;
|
||||
private final static int TEXTURE_HEIGHT = TextureItem.TEXTURE_HEIGHT;
|
||||
private final static float SCALE = 8.0f;
|
||||
|
||||
SymbolItem symbols;
|
||||
|
||||
private final Canvas mCanvas;
|
||||
private final Rect mRect = new Rect();
|
||||
|
||||
public SymbolLayer() {
|
||||
type = Layer.SYMBOL;
|
||||
fixed = true;
|
||||
mCanvas = new Canvas();
|
||||
}
|
||||
|
||||
public void addSymbol(SymbolItem item) {
|
||||
|
||||
verticesCnt += 4;
|
||||
|
||||
for (SymbolItem it = symbols; it != null; it = it.next) {
|
||||
if (it.bitmap == item.bitmap) {
|
||||
// insert after same bitmap
|
||||
item.next = it.next;
|
||||
it.next = item;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
item.next = symbols;
|
||||
symbols = item;
|
||||
}
|
||||
|
||||
public void addDrawable(Drawable drawable, int state, float x, float y) {
|
||||
|
||||
verticesCnt += 4;
|
||||
|
||||
SymbolItem item = SymbolItem.pool.get();
|
||||
item.drawable = drawable;
|
||||
item.x = x;
|
||||
item.y = y;
|
||||
item.billboard = true;
|
||||
item.state = state;
|
||||
|
||||
for (SymbolItem it = symbols; it != null; it = it.next) {
|
||||
if (it.drawable == item.drawable && it.state == item.state) {
|
||||
// insert after same drawable
|
||||
item.next = it.next;
|
||||
it.next = item;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
item.next = symbols;
|
||||
symbols = item;
|
||||
}
|
||||
|
||||
private final static int LBIT_MASK = 0xfffffffe;
|
||||
|
||||
// TODO reuse texture when only symbol position changed
|
||||
@Override
|
||||
public boolean prepare() {
|
||||
|
||||
short numIndices = 0;
|
||||
short offsetIndices = 0;
|
||||
short curIndices = 0;
|
||||
|
||||
curItem = VertexItem.pool.get();
|
||||
vertexItems = curItem;
|
||||
VertexItem si = curItem;
|
||||
|
||||
int pos = si.used;
|
||||
short buf[] = si.vertices;
|
||||
|
||||
int advanceY = 0;
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
|
||||
TextureItem to = TextureItem.get(true);
|
||||
textures = to;
|
||||
mCanvas.setBitmap(to.bitmap);
|
||||
|
||||
for (SymbolItem it = symbols; it != null;) {
|
||||
float width, height;
|
||||
|
||||
if (it.bitmap != null) {
|
||||
// add bitmap
|
||||
width = it.bitmap.getWidth();
|
||||
height = it.bitmap.getHeight();
|
||||
} else {
|
||||
width = it.drawable.getIntrinsicWidth();
|
||||
height = it.drawable.getIntrinsicHeight();
|
||||
}
|
||||
|
||||
if (height > advanceY)
|
||||
advanceY = (int) height;
|
||||
|
||||
if (x + width > TEXTURE_WIDTH) {
|
||||
x = 0;
|
||||
y += advanceY;
|
||||
advanceY = (int) (height + 0.5f);
|
||||
|
||||
}
|
||||
|
||||
if (y + height > TEXTURE_HEIGHT) {
|
||||
Log.d(TAG, "reached max symbols: " + numIndices);
|
||||
|
||||
to.offset = offsetIndices;
|
||||
to.vertices = curIndices;
|
||||
|
||||
numIndices += curIndices;
|
||||
offsetIndices = numIndices;
|
||||
curIndices = 0;
|
||||
|
||||
to.next = TextureItem.get(true);
|
||||
to = to.next;
|
||||
|
||||
mCanvas.setBitmap(to.bitmap);
|
||||
|
||||
x = 0;
|
||||
y = 0;
|
||||
advanceY = (int) height;
|
||||
}
|
||||
|
||||
if (it.bitmap != null) {
|
||||
mCanvas.drawBitmap(it.bitmap, x, y, null);
|
||||
} else {
|
||||
it.drawable.copyBounds(mRect);
|
||||
it.drawable.setBounds((int) x, (int) y, (int) (x + width), (int) (y + height));
|
||||
it.drawable.draw(mCanvas);
|
||||
it.drawable.setBounds(mRect);
|
||||
}
|
||||
|
||||
short x1, y1, x2, y2;
|
||||
|
||||
if (it.bitmap != null) {
|
||||
float hw = width / 2.0f;
|
||||
float hh = height / 2.0f;
|
||||
x1 = (short) (SCALE * (-hw));
|
||||
x2 = (short) (SCALE * (hw));
|
||||
y1 = (short) (SCALE * (hh));
|
||||
y2 = (short) (SCALE * (-hh));
|
||||
} else {
|
||||
// use drawable offsets (for marker hotspot)
|
||||
x2 = (short) (SCALE * (mRect.left));
|
||||
y2 = (short) (SCALE * (mRect.top));
|
||||
x1 = (short) (SCALE * (mRect.right));
|
||||
y1 = (short) (SCALE * (mRect.bottom));
|
||||
|
||||
}
|
||||
|
||||
short u1 = (short) (SCALE * x);
|
||||
short v1 = (short) (SCALE * y);
|
||||
short u2 = (short) (SCALE * (x + width));
|
||||
short v2 = (short) (SCALE * (y + height));
|
||||
|
||||
// add symbol items referencing the same bitmap / drawable
|
||||
for (SymbolItem it2 = it;; it2 = it2.next) {
|
||||
|
||||
if (it2 == null
|
||||
|| (it.drawable != null && it2.drawable != it.drawable)
|
||||
|| (it.bitmap != null && it2.bitmap != it.bitmap)) {
|
||||
it = it2;
|
||||
break;
|
||||
}
|
||||
|
||||
// add vertices
|
||||
short tx = (short) ((int) (SCALE * it2.x) & LBIT_MASK | (it2.billboard ? 1 : 0));
|
||||
short ty = (short) (SCALE * it2.y);
|
||||
|
||||
if (pos == VertexItem.SIZE) {
|
||||
si.used = VertexItem.SIZE;
|
||||
si = si.next = VertexItem.pool.get();
|
||||
buf = si.vertices;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
// top-left
|
||||
buf[pos++] = tx;
|
||||
buf[pos++] = ty;
|
||||
buf[pos++] = x1;
|
||||
buf[pos++] = y1;
|
||||
buf[pos++] = u1;
|
||||
buf[pos++] = v2;
|
||||
// bot-left
|
||||
buf[pos++] = tx;
|
||||
buf[pos++] = ty;
|
||||
buf[pos++] = x1;
|
||||
buf[pos++] = y2;
|
||||
buf[pos++] = u1;
|
||||
buf[pos++] = v1;
|
||||
// top-right
|
||||
buf[pos++] = tx;
|
||||
buf[pos++] = ty;
|
||||
buf[pos++] = x2;
|
||||
buf[pos++] = y1;
|
||||
buf[pos++] = u2;
|
||||
buf[pos++] = v2;
|
||||
// bot-right
|
||||
buf[pos++] = tx;
|
||||
buf[pos++] = ty;
|
||||
buf[pos++] = x2;
|
||||
buf[pos++] = y2;
|
||||
buf[pos++] = u2;
|
||||
buf[pos++] = v1;
|
||||
|
||||
// six elements used to draw the four vertices
|
||||
curIndices += TextureRenderer.INDICES_PER_SPRITE;
|
||||
}
|
||||
x += width;
|
||||
}
|
||||
|
||||
to.offset = offsetIndices;
|
||||
to.vertices = curIndices;
|
||||
|
||||
si.used = pos;
|
||||
curItem = si;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clear() {
|
||||
TextureItem.releaseAll(textures);
|
||||
|
||||
SymbolItem.pool.releaseAll(symbols);
|
||||
VertexItem.pool.releaseAll(vertexItems);
|
||||
textures = null;
|
||||
symbols = null;
|
||||
vertexItems = null;
|
||||
verticesCnt = 0;
|
||||
}
|
||||
}
|
||||
146
src/org/oscim/renderer/sublayers/TextItem.java
Normal file
146
src/org/oscim/renderer/sublayers/TextItem.java
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2012 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.sublayers;
|
||||
|
||||
import org.oscim.theme.renderinstruction.Text;
|
||||
import org.oscim.utils.pool.Inlist;
|
||||
import org.oscim.utils.pool.SyncPool;
|
||||
|
||||
public class TextItem extends Inlist<TextItem> {
|
||||
//private final static String TAG = TextItem.class.getName();
|
||||
private final static int MAX_POOL = 250;
|
||||
|
||||
public final static SyncPool<TextItem> pool = new SyncPool<TextItem>(MAX_POOL) {
|
||||
|
||||
@Override
|
||||
protected TextItem createItem() {
|
||||
return new TextItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clearItem(TextItem ti) {
|
||||
// drop references
|
||||
ti.string = null;
|
||||
ti.text = null;
|
||||
ti.n1 = null;
|
||||
ti.n2 = null;
|
||||
}
|
||||
};
|
||||
|
||||
public static TextItem copy(TextItem orig) {
|
||||
|
||||
TextItem ti = pool.get();
|
||||
|
||||
ti.x = orig.x;
|
||||
ti.y = orig.y;
|
||||
|
||||
ti.x1 = orig.x1;
|
||||
ti.y1 = orig.y1;
|
||||
ti.x2 = orig.x2;
|
||||
ti.y2 = orig.y2;
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
public static boolean shareText(TextItem ti1, TextItem ti2){
|
||||
if (ti1.text != ti2.text)
|
||||
return false;
|
||||
|
||||
if (ti1.string == ti2.string)
|
||||
return true;
|
||||
|
||||
if (ti1.string.equals(ti2.string)){
|
||||
// make strings unique, should be done only once..
|
||||
ti1.string = ti2.string;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public TextItem set(float x, float y, String string, Text text) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.string = string;
|
||||
this.text = text;
|
||||
this.x1 = 0;
|
||||
this.y1 = 0;
|
||||
this.x2 = 1;
|
||||
this.y2 = 0;
|
||||
this.width = text.paint.measureText(string);
|
||||
return this;
|
||||
}
|
||||
|
||||
public static boolean bboxOverlaps(TextItem it1, TextItem it2, float add) {
|
||||
if (it1.y1 < it1.y2) {
|
||||
if (it2.y1 < it2.y2)
|
||||
return (it1.x1 - add < it2.x2)
|
||||
&& (it2.x1 < it1.x2 + add)
|
||||
&& (it1.y1 - add < it2.y2)
|
||||
&& (it2.y1 < it1.y2 + add);
|
||||
|
||||
// flip it2
|
||||
return (it1.x1 - add < it2.x2)
|
||||
&& (it2.x1 < it1.x2 + add)
|
||||
&& (it1.y1 - add < it2.y1)
|
||||
&& (it2.y2 < it1.y2 + add);
|
||||
}
|
||||
|
||||
// flip it1
|
||||
if (it2.y1 < it2.y2)
|
||||
return (it1.x1 - add < it2.x2)
|
||||
&& (it2.x1 < it1.x2 + add)
|
||||
&& (it1.y2 - add < it2.y2)
|
||||
&& (it2.y1 < it1.y1 + add);
|
||||
|
||||
// flip both
|
||||
return (it1.x1 - add < it2.x2)
|
||||
&& (it2.x1 < it1.x2 + add)
|
||||
&& (it1.y2 - add < it2.y1)
|
||||
&& (it2.y2 < it1.y1 + add);
|
||||
}
|
||||
|
||||
// link to next node
|
||||
//public TextItem next;
|
||||
|
||||
// center
|
||||
public float x, y;
|
||||
|
||||
// label text
|
||||
public String string;
|
||||
|
||||
// text style
|
||||
public Text text;
|
||||
|
||||
// label width
|
||||
public float width;
|
||||
|
||||
// left and right corner of segment
|
||||
public float x1, y1, x2, y2;
|
||||
|
||||
// segment length
|
||||
public short length;
|
||||
|
||||
// link to next/prev label of the way
|
||||
public TextItem n1;
|
||||
public TextItem n2;
|
||||
|
||||
public byte edges;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return x + " " + y + " " + string;
|
||||
}
|
||||
}
|
||||
283
src/org/oscim/renderer/sublayers/TextLayer.java
Normal file
283
src/org/oscim/renderer/sublayers/TextLayer.java
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright 2012 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.sublayers;
|
||||
|
||||
import static org.oscim.renderer.GLRenderer.COORD_SCALE;
|
||||
import static org.oscim.renderer.sublayers.TextureItem.TEXTURE_HEIGHT;
|
||||
import static org.oscim.renderer.sublayers.TextureItem.TEXTURE_WIDTH;
|
||||
import android.graphics.Canvas;
|
||||
|
||||
public final class TextLayer extends TextureLayer {
|
||||
|
||||
//private static String TAG = TextureLayer.class.getName();
|
||||
|
||||
private final static int LBIT_MASK = 0xfffffffe;
|
||||
|
||||
private static int mFontPadX = 1;
|
||||
//private static int mFontPadY = 1;
|
||||
|
||||
public TextItem labels;
|
||||
private final Canvas mCanvas;
|
||||
|
||||
public TextItem getLabels() {
|
||||
return labels;
|
||||
}
|
||||
|
||||
public TextLayer() {
|
||||
type = Layer.SYMBOL;
|
||||
//mCanvas = Graphics.res.getCanvas();
|
||||
mCanvas = new Canvas();
|
||||
fixed = true;
|
||||
}
|
||||
|
||||
public void addText(TextItem item) {
|
||||
TextItem it = labels;
|
||||
|
||||
for (; it != null; it = it.next) {
|
||||
|
||||
if (item.text == it.text) {
|
||||
while (it.next != null
|
||||
// break if next item uses different text style
|
||||
&& item.text == it.next.text
|
||||
// check same string instance
|
||||
&& item.string != it.string
|
||||
// check same string
|
||||
&& !item.string.equals(it.string))
|
||||
it = it.next;
|
||||
|
||||
// unify duplicate string :)
|
||||
// Note: this is required for 'packing test' in prepare to work!
|
||||
if (item.string != it.string && item.string.equals(it.string))
|
||||
item.string = it.string;
|
||||
|
||||
// insert after text of same type and/or before same string
|
||||
item.next = it.next;
|
||||
it.next = item;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
item.next = labels;
|
||||
labels = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepare() {
|
||||
|
||||
short numIndices = 0;
|
||||
short offsetIndices = 0;
|
||||
|
||||
VertexItem vi = vertexItems = VertexItem.pool.get();
|
||||
int pos = vi.used; // 0
|
||||
short buf[] = vi.vertices;
|
||||
|
||||
verticesCnt = 0;
|
||||
|
||||
int advanceY = 0;
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float yy;
|
||||
|
||||
TextureItem to = TextureItem.get(true);
|
||||
textures = to;
|
||||
mCanvas.setBitmap(to.bitmap);
|
||||
|
||||
for (TextItem it = labels; it != null;) {
|
||||
|
||||
float width = it.width + 2 * mFontPadX;
|
||||
float height = (int) (it.text.fontHeight) + 0.5f;
|
||||
|
||||
if (height > advanceY)
|
||||
advanceY = (int) height;
|
||||
|
||||
if (x + width > TEXTURE_WIDTH) {
|
||||
x = 0;
|
||||
y += advanceY;
|
||||
advanceY = (int) (height + 0.5f);
|
||||
|
||||
if (y + height > TEXTURE_HEIGHT) {
|
||||
to.offset = offsetIndices;
|
||||
to.vertices = (short) (numIndices - offsetIndices);
|
||||
offsetIndices = numIndices;
|
||||
|
||||
to.next = TextureItem.get(true);
|
||||
to = to.next;
|
||||
|
||||
mCanvas.setBitmap(to.bitmap);
|
||||
|
||||
x = 0;
|
||||
y = 0;
|
||||
advanceY = (int) height;
|
||||
}
|
||||
}
|
||||
|
||||
//yy = y + (height - 1) - it.text.fontDescent - mFontPadY;
|
||||
yy = y + height - it.text.fontDescent; // - mFontPadY;
|
||||
|
||||
if (it.text.stroke != null)
|
||||
mCanvas.drawText(it.string, x + it.width / 2, yy, it.text.stroke);
|
||||
|
||||
mCanvas.drawText(it.string, x + it.width / 2, yy, it.text.paint);
|
||||
|
||||
// FIXME !!!
|
||||
if (width > TEXTURE_WIDTH)
|
||||
width = TEXTURE_WIDTH;
|
||||
|
||||
float hw = width / 2.0f;
|
||||
float hh = height / 2.0f;
|
||||
|
||||
float hh2 = hh;
|
||||
//if (!it.text.caption) {
|
||||
// // displace by baseline
|
||||
// float desc = 0; //(hh - (height - it.text.fontDescent) / 2);
|
||||
//
|
||||
// //float desc = it.text.fontDescent / 2;
|
||||
// hh2 = hh + desc;
|
||||
// hh = hh - desc;
|
||||
//}
|
||||
|
||||
// texture coordinates
|
||||
short u1 = (short) (COORD_SCALE * x);
|
||||
short v1 = (short) (COORD_SCALE * y);
|
||||
short u2 = (short) (COORD_SCALE * (x + width));
|
||||
short v2 = (short) (COORD_SCALE * (y + height));
|
||||
|
||||
while (it != null) {
|
||||
|
||||
short x1, x2, x3, x4, y1, y3, y2, y4;
|
||||
|
||||
if (it.text.caption) {
|
||||
//if (it.origin == 0) {
|
||||
x1 = x3 = (short) (COORD_SCALE * -hw);
|
||||
x2 = x4 = (short) (COORD_SCALE * hw);
|
||||
y1 = y2 = (short) (COORD_SCALE * hh);
|
||||
y3 = y4 = (short) (COORD_SCALE * -hh);
|
||||
//} else {
|
||||
// x1 = x3 = (short) (SCALE * 0);
|
||||
// x2 = x4 = (short) (SCALE * width);
|
||||
// y1 = y2 = (short) (SCALE * 0);
|
||||
// y3 = y4 = (short) (SCALE * -height);
|
||||
//}
|
||||
} else {
|
||||
float vx = it.x1 - it.x2;
|
||||
float vy = it.y1 - it.y2;
|
||||
float a = (float) Math.sqrt(vx * vx + vy * vy);
|
||||
vx = vx / a;
|
||||
vy = vy / a;
|
||||
|
||||
float ux = -vy * hh;
|
||||
float uy = vx * hh;
|
||||
|
||||
float ux2 = -vy * hh2;
|
||||
float uy2 = vx * hh2;
|
||||
|
||||
vx *= hw;
|
||||
vy *= hw;
|
||||
|
||||
// top-left
|
||||
x1 = (short) (COORD_SCALE * (vx - ux));
|
||||
y1 = (short) (COORD_SCALE * (vy - uy));
|
||||
// top-right
|
||||
x2 = (short) (COORD_SCALE * (-vx - ux));
|
||||
y2 = (short) (COORD_SCALE * (-vy - uy));
|
||||
// bot-right
|
||||
x4 = (short) (COORD_SCALE * (-vx + ux2));
|
||||
y4 = (short) (COORD_SCALE * (-vy + uy2));
|
||||
// bot-left
|
||||
x3 = (short) (COORD_SCALE * (vx + ux2));
|
||||
y3 = (short) (COORD_SCALE * (vy + uy2));
|
||||
}
|
||||
|
||||
// add vertices
|
||||
int tmp = (int) (COORD_SCALE * it.x) & LBIT_MASK;
|
||||
short tx = (short) (tmp | (it.text.caption ? 1 : 0));
|
||||
short ty = (short) (COORD_SCALE * it.y);
|
||||
|
||||
if (pos == VertexItem.SIZE) {
|
||||
vi.used = VertexItem.SIZE;
|
||||
vi = vi.next = VertexItem.pool.get();
|
||||
buf = vi.vertices;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
// top-left
|
||||
buf[pos++] = tx;
|
||||
buf[pos++] = ty;
|
||||
buf[pos++] = x1;
|
||||
buf[pos++] = y1;
|
||||
buf[pos++] = u1;
|
||||
buf[pos++] = v2;
|
||||
// bot-left
|
||||
buf[pos++] = tx;
|
||||
buf[pos++] = ty;
|
||||
buf[pos++] = x3;
|
||||
buf[pos++] = y3;
|
||||
buf[pos++] = u1;
|
||||
buf[pos++] = v1;
|
||||
// top-right
|
||||
buf[pos++] = tx;
|
||||
buf[pos++] = ty;
|
||||
buf[pos++] = x2;
|
||||
buf[pos++] = y2;
|
||||
buf[pos++] = u2;
|
||||
buf[pos++] = v2;
|
||||
// bot-right
|
||||
buf[pos++] = tx;
|
||||
buf[pos++] = ty;
|
||||
buf[pos++] = x4;
|
||||
buf[pos++] = y4;
|
||||
buf[pos++] = u2;
|
||||
buf[pos++] = v1;
|
||||
|
||||
// six indices to draw the four vertices
|
||||
numIndices += TextureRenderer.INDICES_PER_SPRITE;
|
||||
verticesCnt += 4;
|
||||
|
||||
if (it.next == null || (it.next.text != it.text)
|
||||
|| (it.next.string != it.string)) {
|
||||
it = it.next;
|
||||
break;
|
||||
}
|
||||
it = it.next;
|
||||
|
||||
}
|
||||
x += width;
|
||||
}
|
||||
|
||||
vi.used = pos;
|
||||
|
||||
to.offset = offsetIndices;
|
||||
to.vertices = (short) (numIndices - offsetIndices);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
TextureItem.releaseAll(textures);
|
||||
labels = null;
|
||||
|
||||
TextItem.pool.releaseAll(labels);
|
||||
VertexItem.pool.releaseAll(vertexItems);
|
||||
textures = null;
|
||||
vertexItems = null;
|
||||
verticesCnt = 0;
|
||||
}
|
||||
|
||||
public void clearLabels() {
|
||||
TextItem.pool.releaseAll(labels);
|
||||
labels = null;
|
||||
}
|
||||
}
|
||||
213
src/org/oscim/renderer/sublayers/TextureAtlas.java
Normal file
213
src/org/oscim/renderer/sublayers/TextureAtlas.java
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
// ported from:
|
||||
/* ============================================================================
|
||||
* Freetype GL - A C OpenGL Freetype engine
|
||||
* Platform: Any
|
||||
* WWW: http://code.google.com/p/freetype-gl/
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright 2011,2012 Nicolas P. Rougier. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are
|
||||
* those of the authors and should not be interpreted as representing official
|
||||
* policies, either expressed or implied, of Nicolas P. Rougier.
|
||||
* ============================================================================
|
||||
*
|
||||
* This source is based on the article by Jukka Jylanki :
|
||||
* "A Thousand Ways to Pack the Bin - A Practical Approach to
|
||||
* Two-Dimensional Rectangle Bin Packing", February 27, 2010.
|
||||
*
|
||||
* More precisely, this is an implementation of the Skyline Bottom-Left
|
||||
* algorithm based on C++ sources provided by Jukka Jylanki at:
|
||||
* http://clb.demon.fi/files/RectangleBinPack/
|
||||
*
|
||||
* ============================================================================
|
||||
*/
|
||||
package org.oscim.renderer.sublayers;
|
||||
|
||||
import org.oscim.utils.pool.Inlist;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
public class TextureAtlas {
|
||||
/** Allocated slots */
|
||||
public Slot mSlots;
|
||||
private Rect mRects;
|
||||
|
||||
/** Width (in pixels) of the underlying texture */
|
||||
final int mWidth;
|
||||
|
||||
/** Height (in pixels) of the underlying texture */
|
||||
final int mHeight;
|
||||
|
||||
/** Depth (in bytes) of the underlying texture */
|
||||
final int mDepth;
|
||||
|
||||
/** Allocated surface size */
|
||||
int mUsed;
|
||||
|
||||
/** Texture identity (OpenGL) */
|
||||
int mId;
|
||||
|
||||
/** Atlas data */
|
||||
Bitmap mData;
|
||||
|
||||
public static class Slot extends Inlist<Slot> {
|
||||
public int x, y, w;
|
||||
|
||||
public Slot(int x, int y, int w) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.w = w;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Rect extends Inlist<Rect> {
|
||||
public int x, y, w, h;
|
||||
}
|
||||
|
||||
private TextureAtlas(int width, int height, int depth) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mDepth = depth;
|
||||
mSlots = new Slot(1, 1, width - 2);
|
||||
}
|
||||
|
||||
public Rect getRegion(int width, int height) {
|
||||
int y, bestHeight, bestWidth;
|
||||
Slot slot, prev;
|
||||
Rect r = new Rect();
|
||||
r.w = width;
|
||||
r.h = height;
|
||||
|
||||
bestHeight = Integer.MAX_VALUE;
|
||||
bestWidth = Integer.MAX_VALUE;
|
||||
|
||||
Slot bestSlot = null;
|
||||
|
||||
for (slot = mSlots; slot != null; slot = slot.next) {
|
||||
// fit width
|
||||
if ((slot.x + width) > (mWidth - 1))
|
||||
continue;
|
||||
|
||||
// fit height
|
||||
y = slot.y;
|
||||
int widthLeft = width;
|
||||
|
||||
Slot fit = slot;
|
||||
while (widthLeft > 0) {
|
||||
if (fit.y > y)
|
||||
y = fit.y;
|
||||
|
||||
if ((y + height) > (mHeight - 1)) {
|
||||
y = -1;
|
||||
break;
|
||||
}
|
||||
widthLeft -= fit.w;
|
||||
|
||||
fit = fit.next;
|
||||
}
|
||||
|
||||
if (y < 0)
|
||||
continue;
|
||||
|
||||
int h = y + height;
|
||||
if ((h < bestHeight) || ((h == bestHeight) && (slot.w < bestWidth))) {
|
||||
bestHeight = h;
|
||||
bestSlot = slot;
|
||||
bestWidth = slot.w;
|
||||
r.x = slot.x;
|
||||
r.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestSlot == null)
|
||||
return null;
|
||||
|
||||
Slot curSlot = new Slot(r.x, r.y + height, width);
|
||||
mSlots = Inlist.prependRelative(mSlots, curSlot, bestSlot);
|
||||
|
||||
// split
|
||||
for (prev = curSlot; prev.next != null;) {
|
||||
slot = prev.next;
|
||||
|
||||
int shrink = (prev.x + prev.w) - slot.x;
|
||||
|
||||
if (shrink <= 0)
|
||||
break;
|
||||
|
||||
slot.x += shrink;
|
||||
slot.w -= shrink;
|
||||
if (slot.w > 0)
|
||||
break;
|
||||
|
||||
// erease slot
|
||||
prev.next = slot.next;
|
||||
}
|
||||
|
||||
// merge
|
||||
for (slot = mSlots; slot.next != null;) {
|
||||
Slot next = slot.next;
|
||||
|
||||
if (slot.y == next.y) {
|
||||
slot.w += next.w;
|
||||
|
||||
// erease 'next' slot
|
||||
slot.next = next.next;
|
||||
} else {
|
||||
slot = next;
|
||||
}
|
||||
}
|
||||
|
||||
mUsed += width * height;
|
||||
|
||||
mRects = Inlist.push(mRects, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mRects = null;
|
||||
mSlots = new Slot(1, 1, mWidth - 2);
|
||||
}
|
||||
|
||||
public static TextureAtlas create(int width, int height, int depth) {
|
||||
if (!(depth == 1 || depth == 3 || depth == 4))
|
||||
throw new IllegalArgumentException("invalid depth");
|
||||
|
||||
return new TextureAtlas(width, height, depth);
|
||||
}
|
||||
}
|
||||
245
src/org/oscim/renderer/sublayers/TextureItem.java
Normal file
245
src/org/oscim/renderer/sublayers/TextureItem.java
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright 2012, 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.sublayers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.oscim.utils.GlUtils;
|
||||
import org.oscim.utils.pool.Inlist;
|
||||
import org.oscim.utils.pool.SyncPool;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLUtils;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* @author Hannes Janetzek
|
||||
*/
|
||||
public class TextureItem extends Inlist<TextureItem> {
|
||||
private final static String TAG = TextureItem.class.getName();
|
||||
|
||||
// texture ID
|
||||
public int id;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
// vertex offset from which this texture is referenced
|
||||
public short offset;
|
||||
public short vertices;
|
||||
|
||||
// temporary Bitmap
|
||||
public Bitmap bitmap;
|
||||
|
||||
boolean ownBitmap;
|
||||
|
||||
TextureItem(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public synchronized static void releaseAll(TextureItem ti) {
|
||||
pool.releaseAll(ti);
|
||||
}
|
||||
|
||||
public synchronized static TextureItem get(boolean initBitmap) {
|
||||
TextureItem ti = pool.get();
|
||||
if (initBitmap) {
|
||||
ti.bitmap = getBitmap();
|
||||
ti.bitmap.eraseColor(Color.TRANSPARENT);
|
||||
}
|
||||
return ti;
|
||||
}
|
||||
|
||||
private final static SyncPool<TextureItem> pool = new SyncPool<TextureItem>(20) {
|
||||
|
||||
@Override
|
||||
public void init(int num) {
|
||||
super.init(num);
|
||||
|
||||
int[] textureIds = new int[num];
|
||||
GLES20.glGenTextures(num, textureIds, 0);
|
||||
|
||||
for (int i = 1; i < num; i++) {
|
||||
initTexture(textureIds[i]);
|
||||
TextureItem to = new TextureItem(textureIds[i]);
|
||||
pool = Inlist.push(pool, to);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TextureItem createItem() {
|
||||
return new TextureItem(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clearItem(TextureItem it) {
|
||||
//Log.d(TAG, it.ownBitmap + " " + (it.bitmap == null));
|
||||
if (it.ownBitmap)
|
||||
return;
|
||||
|
||||
releaseBitmap(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void freeItem(TextureItem it) {
|
||||
it.width = -1;
|
||||
it.height = -1;
|
||||
releaseTexture(it);
|
||||
}
|
||||
};
|
||||
|
||||
private static ArrayList<Integer> mFreeTextures = new ArrayList<Integer>();
|
||||
private static ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(10);
|
||||
|
||||
public final static int TEXTURE_WIDTH = 512;
|
||||
public final static int TEXTURE_HEIGHT = 256;
|
||||
|
||||
private static int mBitmapFormat;
|
||||
private static int mBitmapType;
|
||||
private static int mTexCnt = 0;
|
||||
|
||||
static void releaseTexture(TextureItem it) {
|
||||
synchronized (mFreeTextures) {
|
||||
if (it.id >= 0) {
|
||||
mFreeTextures.add(Integer.valueOf(it.id));
|
||||
it.id = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void releaseBitmap(TextureItem it) {
|
||||
synchronized (mBitmaps) {
|
||||
if (it.bitmap != null) {
|
||||
mBitmaps.add(it.bitmap);
|
||||
it.bitmap = null;
|
||||
}
|
||||
it.ownBitmap = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function may only be used in GLRenderer Thread.
|
||||
*
|
||||
* @param to the TextureObjet to compile and upload
|
||||
*/
|
||||
public static void uploadTexture(TextureItem to) {
|
||||
|
||||
// free unused textures, find a better place for this TODO
|
||||
synchronized (mFreeTextures) {
|
||||
int size = mFreeTextures.size();
|
||||
int[] tmp = new int[size];
|
||||
for (int i = 0; i < size; i++)
|
||||
tmp[i] = mFreeTextures.get(i).intValue();
|
||||
mFreeTextures.clear();
|
||||
GLES20.glDeleteTextures(size, tmp, 0);
|
||||
}
|
||||
|
||||
if (to.id < 0) {
|
||||
mTexCnt++;
|
||||
int[] textureIds = new int[1];
|
||||
GLES20.glGenTextures(1, textureIds, 0);
|
||||
to.id = textureIds[0];
|
||||
initTexture(to.id);
|
||||
if (TextureRenderer.debug)
|
||||
Log.d(TAG, pool.getCount() + " " + pool.getFill()
|
||||
+ " " + mTexCnt + " new texture " + to.id);
|
||||
}
|
||||
|
||||
uploadTexture(to, to.bitmap, mBitmapFormat, mBitmapType,
|
||||
TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
if (!to.ownBitmap)
|
||||
TextureItem.releaseBitmap(to);
|
||||
}
|
||||
|
||||
public static void uploadTexture(TextureItem to, Bitmap bitmap,
|
||||
int format, int type, int w, int h) {
|
||||
|
||||
if (to == null) {
|
||||
Log.d(TAG, "no texture!");
|
||||
return;
|
||||
}
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, to.id);
|
||||
|
||||
if (to.ownBitmap) {
|
||||
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
|
||||
|
||||
} else if (to.width == w && to.height == h) {
|
||||
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, bitmap, format, type);
|
||||
|
||||
} else {
|
||||
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, format, bitmap, type, 0);
|
||||
to.width = w;
|
||||
to.height = h;
|
||||
}
|
||||
|
||||
if (TextureRenderer.debug)
|
||||
GlUtils.checkGlError(TAG);
|
||||
}
|
||||
|
||||
static void initTexture(int id) {
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, id);
|
||||
|
||||
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.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
|
||||
GLES20.GL_CLAMP_TO_EDGE); // Set U Wrapping
|
||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
|
||||
GLES20.GL_CLAMP_TO_EDGE); // Set V Wrapping
|
||||
}
|
||||
|
||||
static void init(int num) {
|
||||
pool.init(num);
|
||||
|
||||
mBitmaps = new ArrayList<Bitmap>(10);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(
|
||||
TEXTURE_WIDTH, TEXTURE_HEIGHT,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
|
||||
mBitmaps.add(bitmap);
|
||||
}
|
||||
|
||||
mBitmapFormat = GLUtils.getInternalFormat(mBitmaps.get(0));
|
||||
mBitmapType = GLUtils.getType(mBitmaps.get(0));
|
||||
|
||||
mTexCnt = num;
|
||||
}
|
||||
|
||||
static Bitmap getBitmap() {
|
||||
synchronized (mBitmaps) {
|
||||
|
||||
int size = mBitmaps.size();
|
||||
if (size == 0) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(
|
||||
TEXTURE_WIDTH, TEXTURE_HEIGHT,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
|
||||
if (TextureRenderer.debug)
|
||||
Log.d(TAG, "alloc bitmap: " +
|
||||
android.os.Debug.getNativeHeapAllocatedSize() / (1024 * 1024));
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
return mBitmaps.remove(size - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
45
src/org/oscim/renderer/sublayers/TextureLayer.java
Normal file
45
src/org/oscim/renderer/sublayers/TextureLayer.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012, 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.sublayers;
|
||||
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* @author Hannes Janetzek
|
||||
*/
|
||||
public abstract class TextureLayer extends Layer {
|
||||
// holds textures and offset in vbo
|
||||
public TextureItem textures;
|
||||
|
||||
// scale mode
|
||||
public boolean fixed;
|
||||
|
||||
/**
|
||||
* @param sbuf
|
||||
* buffer to add vertices
|
||||
*/
|
||||
@Override
|
||||
protected void compile(ShortBuffer sbuf) {
|
||||
|
||||
for (TextureItem to = textures; to != null; to = to.next)
|
||||
TextureItem.uploadTexture(to);
|
||||
|
||||
// add vertices to vbo
|
||||
Layers.addPoolItems(this, sbuf);
|
||||
}
|
||||
|
||||
abstract public boolean prepare();
|
||||
}
|
||||
144
src/org/oscim/renderer/sublayers/TextureRenderer.java
Normal file
144
src/org/oscim/renderer/sublayers/TextureRenderer.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2012, 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.sublayers;
|
||||
|
||||
import static org.oscim.renderer.GLRenderer.COORD_SCALE;
|
||||
import static org.oscim.renderer.sublayers.TextureItem.TEXTURE_HEIGHT;
|
||||
import static org.oscim.renderer.sublayers.TextureItem.TEXTURE_WIDTH;
|
||||
|
||||
import org.oscim.renderer.GLRenderer;
|
||||
import org.oscim.renderer.GLRenderer.Matrices;
|
||||
import org.oscim.renderer.GLState;
|
||||
import org.oscim.utils.GlUtils;
|
||||
|
||||
import android.opengl.GLES20;
|
||||
|
||||
public final class TextureRenderer {
|
||||
//private final static String TAG = TextureRenderer.class.getName();
|
||||
public final static boolean debug = false;
|
||||
|
||||
private static int mTextureProgram;
|
||||
private static int hTextureMVMatrix;
|
||||
private static int hTextureProjMatrix;
|
||||
private static int hTextureVertex;
|
||||
private static int hTextureScale;
|
||||
private static int hTextureScreenScale;
|
||||
private static int hTextureTexCoord;
|
||||
|
||||
public final static int INDICES_PER_SPRITE = 6;
|
||||
final static int VERTICES_PER_SPRITE = 4;
|
||||
final static int SHORTS_PER_VERTICE = 6;
|
||||
|
||||
static void init() {
|
||||
mTextureProgram = GlUtils.createProgram(textVertexShader,
|
||||
textFragmentShader);
|
||||
|
||||
hTextureMVMatrix = GLES20.glGetUniformLocation(mTextureProgram, "u_mv");
|
||||
hTextureProjMatrix = GLES20.glGetUniformLocation(mTextureProgram, "u_proj");
|
||||
hTextureScale = GLES20.glGetUniformLocation(mTextureProgram, "u_scale");
|
||||
hTextureScreenScale = GLES20.glGetUniformLocation(mTextureProgram, "u_swidth");
|
||||
hTextureVertex = GLES20.glGetAttribLocation(mTextureProgram, "vertex");
|
||||
hTextureTexCoord = GLES20.glGetAttribLocation(mTextureProgram, "tex_coord");
|
||||
}
|
||||
|
||||
public static Layer draw(Layer layer, float scale, Matrices m) {
|
||||
GLState.test(false, false);
|
||||
GLState.blend(true);
|
||||
|
||||
GLState.useProgram(mTextureProgram);
|
||||
|
||||
GLState.enableVertexArrays(hTextureTexCoord, hTextureVertex);
|
||||
|
||||
TextureLayer tl = (TextureLayer) layer;
|
||||
|
||||
if (tl.fixed)
|
||||
GLES20.glUniform1f(hTextureScale, (float) Math.sqrt(scale));
|
||||
else
|
||||
GLES20.glUniform1f(hTextureScale, 1);
|
||||
|
||||
GLES20.glUniform1f(hTextureScreenScale, 1f / GLRenderer.screenWidth);
|
||||
|
||||
m.proj.setAsUniform(hTextureProjMatrix);
|
||||
m.mvp.setAsUniform(hTextureMVMatrix);
|
||||
|
||||
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, GLRenderer.mQuadIndicesID);
|
||||
|
||||
for (TextureItem ti = tl.textures; ti != null; ti = ti.next) {
|
||||
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, ti.id);
|
||||
int maxVertices = GLRenderer.maxQuads * INDICES_PER_SPRITE;
|
||||
|
||||
// draw up to maxVertices in each iteration
|
||||
for (int i = 0; i < ti.vertices; i += maxVertices) {
|
||||
// to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8)
|
||||
int off = (ti.offset + i) * 8 + tl.offset;
|
||||
|
||||
GLES20.glVertexAttribPointer(hTextureVertex, 4,
|
||||
GLES20.GL_SHORT, false, 12, off);
|
||||
|
||||
GLES20.glVertexAttribPointer(hTextureTexCoord, 2,
|
||||
GLES20.GL_SHORT, false, 12, off + 8);
|
||||
|
||||
int numVertices = ti.vertices - i;
|
||||
if (numVertices > maxVertices)
|
||||
numVertices = maxVertices;
|
||||
|
||||
GLES20.glDrawElements(GLES20.GL_TRIANGLES, numVertices,
|
||||
GLES20.GL_UNSIGNED_SHORT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
return layer.next;
|
||||
}
|
||||
|
||||
private final static double TEX_COORD_DIV_X = 1.0 / (TEXTURE_WIDTH * COORD_SCALE);
|
||||
private final static double TEX_COORD_DIV_Y = 1.0 / (TEXTURE_HEIGHT * COORD_SCALE);
|
||||
private final static double COORD_DIV = 1.0 / GLRenderer.COORD_SCALE;
|
||||
|
||||
private final static String textVertexShader = ""
|
||||
+ "precision mediump float; "
|
||||
+ "attribute vec4 vertex;"
|
||||
+ "attribute vec2 tex_coord;"
|
||||
+ "uniform mat4 u_mv;"
|
||||
+ "uniform mat4 u_proj;"
|
||||
+ "uniform float u_scale;"
|
||||
+ "uniform float u_swidth;"
|
||||
+ "varying vec2 tex_c;"
|
||||
+ "const vec2 div = vec2(" + TEX_COORD_DIV_X + "," + TEX_COORD_DIV_Y + ");"
|
||||
+ "const float coord_scale = " + COORD_DIV + ";"
|
||||
+ "void main() {"
|
||||
+ " vec4 pos;"
|
||||
+ " vec2 dir = vertex.zw;"
|
||||
+ " if (mod(vertex.x, 2.0) == 0.0){"
|
||||
+ " pos = u_proj * (u_mv * vec4(vertex.xy + dir * u_scale, 0.0, 1.0));"
|
||||
+ " } else {" // place as billboard
|
||||
+ " vec4 center = u_mv * vec4(vertex.xy, 0.0, 1.0);"
|
||||
+ " pos = u_proj * (center + vec4(dir * (coord_scale * u_swidth), 0.0, 0.0));"
|
||||
+ " }"
|
||||
+ " gl_Position = pos;"
|
||||
+ " tex_c = tex_coord * div;"
|
||||
+ "}";
|
||||
|
||||
private final static String textFragmentShader = ""
|
||||
+ "precision mediump float;"
|
||||
+ "uniform sampler2D tex;"
|
||||
+ "varying vec2 tex_c;"
|
||||
+ "void main() {"
|
||||
+ " gl_FragColor = texture2D(tex, tex_c.xy);"
|
||||
+ "}";
|
||||
}
|
||||
56
src/org/oscim/renderer/sublayers/VertexItem.java
Normal file
56
src/org/oscim/renderer/sublayers/VertexItem.java
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012 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.sublayers;
|
||||
|
||||
import org.oscim.utils.pool.Inlist;
|
||||
import org.oscim.utils.pool.SyncPool;
|
||||
|
||||
public class VertexItem extends Inlist<VertexItem> {
|
||||
|
||||
private static final int MAX_POOL = 500;
|
||||
|
||||
public final static SyncPool<VertexItem> pool = new SyncPool<VertexItem>(MAX_POOL) {
|
||||
|
||||
@Override
|
||||
protected VertexItem createItem() {
|
||||
return new VertexItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clearItem(VertexItem it) {
|
||||
it.used = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add VertexItems back to pool. Make sure to not use the reference afterwards!
|
||||
* i.e.:
|
||||
* vertexItem.release();
|
||||
* vertexItem = null;
|
||||
* */
|
||||
public void release(){
|
||||
VertexItem.pool.releaseAll(this);
|
||||
}
|
||||
|
||||
public final short[] vertices = new short[SIZE];
|
||||
|
||||
public int used;
|
||||
|
||||
// must be multiple of
|
||||
// 4 (LineLayer/PolygonLayer),
|
||||
// 24 (TexLineLayer - one block, i.e. two segments)
|
||||
// 24 (TextureLayer)
|
||||
public static final int SIZE = 360;
|
||||
}
|
||||
Reference in New Issue
Block a user