vtm/vtm/src/org/oscim/renderer/elements/SymbolLayer.java
2014-01-31 03:42:20 +01:00

224 lines
5.5 KiB
Java

/*
* Copyright 2012 Hannes Janetzek
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
* 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.elements;
import java.nio.ShortBuffer;
import org.oscim.backend.canvas.Bitmap;
import org.oscim.core.PointF;
import org.oscim.renderer.atlas.TextureAtlas;
import org.oscim.utils.pool.Inlist;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class SymbolLayer extends TextureLayer {
static final Logger log = LoggerFactory.getLogger(SymbolLayer.class);
private final static float SCALE = 8.0f;
private final static int VERTICES_PER_SPRITE = 4;
private final static int LBIT_MASK = 0xfffffffe;
private TextureItem prevTextures;
private SymbolItem symbols;
public SymbolLayer() {
super(RenderElement.SYMBOL);
fixed = true;
}
// TODO move sorting items to 'prepare'
public void addSymbol(SymbolItem item) {
// needed to calculate 'sbuf' size for compile
numVertices += VERTICES_PER_SPRITE;
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;
}
@Override
protected void compile(ShortBuffer sbuf) {
// offset of layer data in vbo
this.offset = sbuf.position() * 2; //SHORT_BYTES;
short numIndices = 0;
VertexItem si = VertexItem.pool.get();
int pos = 0;
short buf[] = si.vertices;
prevTextures = textures;
textures = null;
TextureItem t = null;
for (SymbolItem it = symbols; it != null;) {
int width = 0, height = 0;
int x = 0;
int y = 0;
if (it.texRegion != null) {
// FIXME this work only with one TextureAtlas per SymbolLayer.
if (textures == null) {
t = it.texRegion.atlas.loadTexture();
// clone TextureItem to use same texID with
// multiple TextureItem
t = TextureItem.clone(t);
textures = Inlist.appendItem(textures, t);
}
TextureAtlas.Rect r = it.texRegion.rect;
x = r.x;
y = r.y;
width = r.w;
height = r.h;
} else if (it.bitmap != null) {
t = getTexture(it.bitmap);
if (t == null) {
t = new TextureItem(it.bitmap);
textures = Inlist.appendItem(textures, t);
t.upload();
t.offset = numIndices;
t.vertices = 0;
}
width = t.width;
height = t.height;
} else { //if (to == null) {
log.debug("Bad SymbolItem");
continue;
}
short u1 = (short) (SCALE * x);
short v1 = (short) (SCALE * y);
short u2 = (short) (SCALE * (x + width));
short v2 = (short) (SCALE * (y + height));
PointF prevOffset = null;
short x1 = 0, y1 = 0, x2 = 0, y2 = 0;
// add symbol items referencing the same bitmap /
for (SymbolItem prev = it; it != null; it = it.next) {
if (prev.bitmap != null && prev.bitmap != it.bitmap)
break;
if (prev.texRegion != null && prev.texRegion != it.texRegion)
break;
if (it == prev || it.offset != prevOffset) {
prevOffset = it.offset;
if (it.offset == null) {
float hw = width / 2f;
float hh = height / 2f;
x1 = (short) (SCALE * (-hw));
x2 = (short) (SCALE * (hw));
y1 = (short) (SCALE * (hh));
y2 = (short) (SCALE * (-hh));
} else {
float hw = (float) (it.offset.x * width);
float hh = (float) (it.offset.y * height);
x1 = (short) (SCALE * (-hw));
x2 = (short) (SCALE * (width - hw));
y1 = (short) (SCALE * (height - hh));
y2 = (short) (SCALE * (-hh));
}
}
// add vertices
short tx = (short) ((int) (SCALE * it.x) & LBIT_MASK
| (it.billboard ? 1 : 0));
short ty = (short) (SCALE * it.y);
if (pos == VertexItem.SIZE) {
sbuf.put(buf, 0, VertexItem.SIZE);
pos = 0;
}
TextureLayer.putSprite(buf, pos, tx, ty,
x1, y1, x2, y2, u1, v1, u2, v2);
pos += TextLayer.VERTICES_PER_SPRITE * 6;
// six elements used to draw the four vertices
t.vertices += TextureLayer.INDICES_PER_SPRITE;
}
numIndices += t.vertices;
}
if (pos > 0)
sbuf.put(buf, 0, pos);
si = VertexItem.pool.release(si);
for (t = prevTextures; t != null; t = t.dispose());
prevTextures = null;
}
private TextureItem getTexture(Bitmap bitmap) {
TextureItem t;
for (t = prevTextures; t != null; t = t.next) {
if (t.bitmap == bitmap) {
prevTextures = Inlist.remove(prevTextures, t);
textures = Inlist.appendItem(textures, t);
t.offset = 0;
t.vertices = 0;
return t;
}
}
return null;
}
public void clearItems() {
symbols = SymbolItem.pool.releaseAll(symbols);
//numVertices = 0;
}
@Override
public void clear() {
// release textures
super.clear();
clearItems();
//symbols = SymbolItem.pool.releaseAll(symbols);
//vertexItems = VertexItem.pool.releaseAll(vertexItems);
//numVertices = 0;
}
@Override
public boolean prepare() {
return true;
}
}