/*
* 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.bucket;
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 SymbolBucket extends TextureBucket {
static final Logger log = LoggerFactory.getLogger(SymbolBucket.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 List<SymbolItem> mSymbols = new List<SymbolItem>();
public SymbolBucket() {
super(RenderBucket.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 : mSymbols) {
if (it.bitmap == item.bitmap) {
/* insert after same bitmap */
item.next = it.next;
it.next = item;
return;
}
}
mSymbols.push(item);
}
public void pushSymbol(SymbolItem item) {
/* needed to calculate 'sbuf' size for compile */
numVertices += VERTICES_PER_SPRITE;
mSymbols.push(item);
}
@Override
protected void compile(ShortBuffer vboData, ShortBuffer iboData) {
/* offset of layer data in vbo */
this.vertexOffset = vboData.position() * 2; //SHORT_BYTES;
int numIndices = 0;
prevTextures = textures;
textures = null;
TextureItem t = null;
for (SymbolItem it = mSymbols.head(); 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) {
/* clone TextureItem to use same texID with
* multiple TextureItem */
t = TextureItem.clone(it.texRegion.texture);
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.offset = numIndices;
t.indices = 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);
vertexItems.add(tx, ty, x1, y1, u1, v2);
vertexItems.add(tx, ty, x1, y2, u1, v1);
vertexItems.add(tx, ty, x2, y1, u2, v2);
vertexItems.add(tx, ty, x2, y2, u2, v1);
/* six elements used to draw the four vertices */
t.indices += TextureBucket.INDICES_PER_SPRITE;
}
numIndices += t.indices;
}
vertexItems.compile(vboData);
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.indices = 0;
return t;
}
}
return null;
}
public void clearItems() {
SymbolItem.pool.releaseAll(mSymbols.clear());
}
@Override
public void clear() {
super.clear();
clearItems();
}
}