vtm/src/org/oscim/renderer/layer/Layers.java

287 lines
6.7 KiB
Java

/*
* 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.layer;
import java.nio.ShortBuffer;
import org.oscim.renderer.BufferObject;
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;
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;
public LineLayer getLineLayer(int level) {
return (LineLayer) getLayer(level, Layer.LINE);
}
public PolygonLayer getPolygonLayer(int level) {
return (PolygonLayer) getLayer(level, Layer.POLYGON);
}
public LineTexLayer getLineTexLayer(int level) {
return (LineTexLayer) getLayer(level, Layer.TEXLINE);
}
// get or add the Line- or PolygonLayer for a level.
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) {
// HACK, see LineTexLayer
//sbuf.position(sbuf.position() + 6);
addPoolItems(l, sbuf);
//l.offset -= 12;
sbuf.position(sbuf.position() + 6);
}
}
//size += addLayerItems(sbuf, baseLayers, Layer.TEXLINE, 0);
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 = 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;
// }
}
}