use TextureRegion (from TextureAtlas) in SymbolLayer

This commit is contained in:
Hannes Janetzek 2013-06-21 09:47:46 +02:00
parent f24240ae27
commit e35d789724
8 changed files with 252 additions and 198 deletions

View File

@ -16,7 +16,7 @@
package org.oscim.layers.labeling;
// TODO
// 1. rewrite :)
// 1. rewrite. seriously
// 1.1 test if label is actually visible
// 2. compare previous to current state
// 2.1 test for new labels to be placed
@ -40,6 +40,7 @@ import org.oscim.renderer.sublayers.Layer;
import org.oscim.renderer.sublayers.Layers;
import org.oscim.renderer.sublayers.LineRenderer;
import org.oscim.renderer.sublayers.PolygonRenderer;
import org.oscim.renderer.sublayers.SymbolItem;
import org.oscim.renderer.sublayers.SymbolLayer;
import org.oscim.renderer.sublayers.TextItem;
import org.oscim.renderer.sublayers.TextLayer;
@ -67,7 +68,6 @@ class TextRenderLayer extends BasicRenderLayer {
private final MapViewPosition mMapViewPosition;
private final TileSet mTileSet;
class TextureLayers {
boolean ready;
@ -317,7 +317,6 @@ class TextRenderLayer extends BasicRenderLayer {
mSquareRadius = mw * mw + mh * mh;
MapTile[] tiles = mTileSet.tiles;
int zoom = tiles[0].zoomLevel;
// scale of tiles zoom-level relative to current position
@ -332,6 +331,9 @@ class TextRenderLayer extends BasicRenderLayer {
if (dbg != null)
Debug.addDebugLayers(dbg);
SymbolLayer sl = mNextLayer.symbolLayer;
sl.clearItems();
mRelabelCnt++;
double tileX = (pos.x * (Tile.SIZE << zoom));
@ -515,7 +517,18 @@ class TextRenderLayer extends BasicRenderLayer {
}
lp = (Label) lp.next;
}
if (ti.text.texture != null){
SymbolItem s = SymbolItem.pool.get();
s.symbol = ti.text.texture;
s.x = l.x;
s.y = l.y;
s.billboard = true;
sl.addSymbol(s);
}
if (!overlaps) {
addLabel(l);
l.item = TextItem.copy(ti);
l.tile = t;
@ -540,6 +553,31 @@ class TextRenderLayer extends BasicRenderLayer {
ti.y2 = tmp;
}
}
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
MapTile t = tiles[i];
if (t.state != MapTile.STATE_READY)
continue;
float dx = (float) (t.tileX * Tile.SIZE - tileX);
float dy = (float) (t.tileY * Tile.SIZE - tileY);
dx = flipLongitude(dx, maxx);
for (SymbolItem ti = t.symbols; ti != null; ti = ti.next) {
if (ti.symbol == null)
continue;
SymbolItem s = SymbolItem.pool.get();
s.symbol = ti.symbol;
s.x = (float)((dx + ti.x) * scale);
s.y = (float)((dy + ti.y) * scale);
s.billboard = true;
sl.addSymbol(s);
}
}
// temporary used Label
mPool.release(l);
@ -656,9 +694,9 @@ class TextRenderLayer extends BasicRenderLayer {
float scale = (float) (mMapPosition.scale / pos.scale);
if (layers.baseLayers != null) {
setMatrix(pos, m, true);
setMatrix(pos, m, true);
if (layers.baseLayers != null) {
for (Layer l = layers.baseLayers; l != null;) {
if (l.type == Layer.POLYGON) {
l = PolygonRenderer.draw(pos, l, m, true, 1, false);

View File

@ -17,6 +17,7 @@ package org.oscim.layers.tile;
import org.oscim.core.Tile;
import org.oscim.renderer.BufferObject;
import org.oscim.renderer.sublayers.Layers;
import org.oscim.renderer.sublayers.SymbolItem;
import org.oscim.renderer.sublayers.TextItem;
import org.oscim.utils.quadtree.QuadTree;
@ -25,7 +26,7 @@ import org.oscim.utils.quadtree.QuadTree;
* TileManager (Main Thread), TileLoader (Worker Threads) and
* Rendering (GL Thread).
*/
public final class MapTile extends Tile {
public class MapTile extends Tile {
public final static int STATE_NONE = 0;
@ -67,9 +68,12 @@ public final class MapTile extends Tile {
public float distance;
/**
* FIXME move to VectorMapTile
* Tile data set by TileLoader.
*/
public TextItem labels;
public SymbolItem symbols;
public Layers layers;
/**
@ -82,8 +86,10 @@ public final class MapTile extends Tile {
*/
public QuadTree<MapTile> rel;
/** to avoid drawing a tile twice per frame
* FIXME what if multiple layers use the same tile? */
/**
* to avoid drawing a tile twice per frame
* FIXME what if multiple layers use the same tile?
*/
int lastDraw = 0;
public final static int PROXY_CHILD1 = 1 << 0;
@ -107,7 +113,7 @@ public final class MapTile extends Tile {
// e.g. x:-1,y:0,z:1 for x:1,y:0
MapTile holder;
MapTile(int tileX, int tileY, byte zoomLevel) {
protected MapTile(int tileX, int tileY, byte zoomLevel) {
super(tileX, tileY, zoomLevel);
this.x = (double) tileX / (1 << zoomLevel);
this.y = (double) tileY / (1 << zoomLevel);
@ -168,10 +174,6 @@ public final class MapTile extends Tile {
labels = t;
}
public void clearState() {
state = STATE_NONE;
}
/**
* @return true if tile is loading, has new data or is ready for rendering
*/
@ -181,12 +183,16 @@ public final class MapTile extends Tile {
public void setLoading() {
//if (state != STATE_NONE)
//Log.d(TAG, "wrong state: " + state);
// Log.wtf(TAG, "wrong state: " + state);
state = STATE_LOADING;
}
void clear(){
public void clearState() {
state = STATE_NONE;
}
protected void clear() {
if (layers != null) {
// TODO move this to layers clear
if (layers.vbo != null) {
@ -195,10 +201,13 @@ public final class MapTile extends Tile {
}
layers.clear();
layers = null;
}
TextItem.pool.releaseAll(labels);
SymbolItem.pool.releaseAll(symbols);
layers = null;
labels = null;
symbols = null;
}
}

View File

@ -30,6 +30,7 @@ import org.oscim.renderer.sublayers.Layers;
import org.oscim.renderer.sublayers.LineLayer;
import org.oscim.renderer.sublayers.LineTexLayer;
import org.oscim.renderer.sublayers.PolygonLayer;
import org.oscim.renderer.sublayers.SymbolItem;
import org.oscim.renderer.sublayers.TextItem;
import org.oscim.theme.IRenderCallback;
import org.oscim.theme.IRenderTheme;
@ -44,6 +45,7 @@ import org.oscim.tilesource.ITileDataSink;
import org.oscim.tilesource.ITileDataSource;
import org.oscim.tilesource.ITileDataSource.QueryResult;
import org.oscim.utils.LineClipper;
import org.oscim.utils.pool.Inlist;
import org.oscim.view.DebugSettings;
import android.util.Log;
@ -139,21 +141,11 @@ public class MapTileLoader extends TileLoader implements IRenderCallback, ITileD
// m.type = GeometryType.POINT;
}
/*
* (non-Javadoc)
* @see org.oscim.layers.tile.TileLoader#cleanup()
*/
@Override
public void cleanup() {
mTileDataSource.destroy();
}
/*
* (non-Javadoc)
* @see
* org.oscim.layers.tile.TileLoader#executeJob(org.oscim.layers.tile.MapTile
* )
*/
@Override
public boolean executeJob(MapTile mapTile) {
@ -338,15 +330,15 @@ public class MapTileLoader extends TileLoader implements IRenderCallback, ITileD
}
private void debugUnmatched(boolean closed, TagSet tags) {
// Log.d(TAG, "DBG way not matched: " + closed + " "
// + Arrays.deepToString(tags));
//
// mTagName = new Tag("name", tags[0].key + ":"
// + tags[0].value, false);
//
// mElement.tags = closed ? debugTagArea : debugTagWay;
// RenderInstruction[] ri = renderTheme.matchElement(mElement, mTile.zoomLevel);
// renderWay(ri);
// Log.d(TAG, "DBG way not matched: " + closed + " "
// + Arrays.deepToString(tags));
//
// mTagName = new Tag("name", tags[0].key + ":"
// + tags[0].value, false);
//
// mElement.tags = closed ? debugTagArea : debugTagWay;
// RenderInstruction[] ri = renderTheme.matchElement(mElement, mTile.zoomLevel);
// renderWay(ri);
}
private void renderWay(RenderInstruction[] ri) {
@ -526,20 +518,17 @@ public class MapTileLoader extends TileLoader implements IRenderCallback, ITileD
@Override
public void renderPointOfInterestSymbol(Symbol symbol) {
// Log.d(TAG, "add symbol");
if (symbol.texture == null){
Log.d(TAG, "missing symbol for " + mElement.tags.asString());
return;
}
SymbolItem it = SymbolItem.pool.get();
it.x = mElement.points[0];
it.y = mElement.points[1];
it.symbol = symbol.texture;
it.billboard = true;
// if (mLayers.textureLayers == null)
// mLayers.textureLayers = new SymbolLayer();
//
// SymbolLayer sl = (SymbolLayer) mLayers.textureLayers;
//
// SymbolItem it = SymbolItem.get();
// it.x = mPoiX;
// it.y = mPoiY;
// it.bitmap = bitmap;
// it.billboard = true;
//
// sl.addSymbol(it);
mTile.symbols = Inlist.push(mTile.symbols, it);
}
@Override

View File

@ -14,11 +14,12 @@
*/
package org.oscim.renderer.sublayers;
import org.oscim.core.PointF;
import org.oscim.renderer.atlas.TextureRegion;
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> {
@ -32,18 +33,18 @@ public class SymbolItem extends Inlist<SymbolItem> {
@Override
protected void clearItem(SymbolItem it) {
// drop references
it.drawable = null;
it.bitmap = null;
it.symbol = null;
it.offset = null;
}
};
public Bitmap bitmap;
public Drawable drawable;
public boolean billboard;
public float x;
public float y;
public boolean billboard;
public int state;
// center, top, bottom, left, right, top-left...
// byte placement;
public TextureRegion symbol;
public Bitmap bitmap;
public PointF offset;
}

View File

@ -16,12 +16,11 @@ package org.oscim.renderer.sublayers;
import java.nio.ShortBuffer;
import org.oscim.renderer.atlas.TextureAtlas;
import org.oscim.utils.pool.Inlist;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
// TODO share one static texture for all poi map symabols
import android.graphics.Bitmap;
import android.util.Log;
public final class SymbolLayer extends TextureLayer {
private final static String TAG = SymbolLayer.class.getSimpleName();
@ -39,6 +38,7 @@ public final class SymbolLayer extends TextureLayer {
// TODO move sorting items to 'prepare'
public void addSymbol(SymbolItem item) {
// needed to calculate 'sbuf' size for compile
verticesCnt += VERTICES_PER_SPRITE;
for (SymbolItem it = symbols; it != null; it = it.next) {
@ -54,117 +54,87 @@ public final class SymbolLayer extends TextureLayer {
symbols = item;
}
public void addDrawable(Drawable drawable, int state, float x, float y) {
verticesCnt += VERTICES_PER_SPRITE;
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;
@Override
public boolean prepare() {
return true;
}
@Override
protected void compile(ShortBuffer sbuf) {
// offset of layer data in vbo
this.offset = sbuf.position() * 2; //SHORT_BYTES;
short numIndices = 0;
//short offsetIndices = 0;
//short curIndices = 0;
//curItem =
//vertexItems = curItem;
VertexItem si = VertexItem.pool.get();
int pos = 0;
short buf[] = si.vertices;
//int advanceY = 0;
final float x = 0;
final float y = 0;
TextureItem prevTextures = textures;
//TextureItem prev = textures;
textures = null;
TextureItem to = null;
//TextureItem to = TextureItem.get(true);
//textures = to;
//mCanvas.setBitmap(to.bitmap);
for (SymbolItem it = symbols; it != null;) {
int width, height;
int width = 0, height = 0;
int x = 0;
int y = 0;
if (it.bitmap != null) {
// add bitmap
if (it.symbol != null) {
// FIXME this work only with one TextureAtlas per
// SymbolLayer.
if (textures == null) {
to = it.symbol.atlas.compileTexture();
// clone TextureItem to use same texID with
// multiple TextureItem
to = new TextureItem(to);
textures = Inlist.append(textures, to);
}
TextureAtlas.Rect r = it.symbol.rect;
x = r.x;
y = r.y;
width = r.w;
height = r.h;
} else if (it.bitmap != null) {
width = it.bitmap.getWidth();
height = it.bitmap.getHeight();
} else {
width = it.drawable.getIntrinsicWidth();
height = it.drawable.getIntrinsicHeight();
}
for (to = prevTextures; to != null; to = to.next){
if (to.bitmap == it.bitmap){
prevTextures = Inlist.remove(prevTextures, to);
to = getTexture(prevTextures, it.bitmap);
if (to == null) {
to = new TextureItem(it.bitmap);
// to.bitmap = it.bitmap;
// to.width = it.bitmap.getWidth();
// to.height = it.bitmap.getHeight();
textures = Inlist.append(textures, to);
break;
TextureItem.uploadTexture(to);
}
to.offset = numIndices;
to.vertices = 0;
}
if (to == null){
to = TextureItem.get(false);
to.bitmap = it.bitmap;
to.width = width;
to.height= height;
textures = Inlist.append(textures, to);
TextureItem.uploadTexture(to);
if (to == null) {
Log.wtf(TAG, "Bad SymbolItem");
continue;
}
to.offset = numIndices;
to.vertices = 0;
short x1, y1, x2, y2;
if (it.bitmap != null) {
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 {
// use drawable offsets (for marker hotspot)
Rect mRect = it.drawable.getBounds();
x2 = (short) (SCALE * (mRect.left));
y2 = (short) (SCALE * (mRect.top));
x1 = (short) (SCALE * (mRect.right));
y1 = (short) (SCALE * (mRect.bottom));
float hw = it.offset.x * width;
float hh = it.offset.y * height;
x1 = (short) (SCALE * (-hw));
x2 = (short) (SCALE * (width - hw));
y1 = (short) (SCALE * (height - hh));
y2 = (short) (SCALE * (-hh));
}
short u1 = (short) (SCALE * x);
@ -172,18 +142,20 @@ public final class SymbolLayer extends TextureLayer {
short u2 = (short) (SCALE * (x + width));
short v2 = (short) (SCALE * (y + height));
// add symbol items referencing the same bitmap / drawable
// add symbol items referencing the same bitmap /
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.bitmap != null && it2.bitmap != it.bitmap)
|| (it.symbol != null && it2.symbol != it.symbol)) {
it = it2;
break;
}
// add vertices
short tx = (short) ((int) (SCALE * it2.x) & LBIT_MASK | (it2.billboard ? 1 : 0));
short tx = (short) ((int) (SCALE * it2.x) & LBIT_MASK
| (it2.billboard ? 1 : 0));
short ty = (short) (SCALE * it2.y);
if (pos == VertexItem.SIZE) {
@ -191,53 +163,18 @@ public final class SymbolLayer extends TextureLayer {
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;
TextureLayer.putSprite(buf, pos, tx, ty,
x1, y1, x2, y2, u1, v1, u2, v2);
// TextureRenderer.VERTICES_PER_SPRITE
// * TextureRenderer.SHORTS_PER_VERTICE;
pos += 24;
// six elements used to draw the four vertices
to.vertices += TextureRenderer.INDICES_PER_SPRITE;
}
numIndices += to.vertices;
//offsetIndices = numIndices;
//to.offset = offsetIndices;
//= curIndices;
//x += width;
}
// if (to != null) {
// to.offset = offsetIndices;
// to.vertices = curIndices;
// }
//si.used = pos;
//curItem = si;
if (pos > 0)
sbuf.put(buf, 0, pos);
@ -248,18 +185,39 @@ public final class SymbolLayer extends TextureLayer {
prevTextures = null;
}
private TextureItem getTexture(TextureItem prevTextures, Bitmap bitmap) {
TextureItem to;
for (to = prevTextures; to != null; to = to.next) {
if (to.bitmap == bitmap) {
prevTextures = Inlist.remove(prevTextures, to);
textures = Inlist.append(textures, to);
break;
}
}
return to;
}
public void clearItems() {
SymbolItem.pool.releaseAll(symbols);
symbols = null;
verticesCnt = 0;
}
@Override
protected void clear() {
public void clear() {
TextureItem.releaseAll(textures);
SymbolItem.pool.releaseAll(symbols);
//VertexItem.pool.releaseAll(vertexItems);
textures = null;
symbols = null;
vertexItems = null;
verticesCnt = 0;
}
@Override
public boolean prepare() {
return true;
}
}

View File

@ -13,7 +13,6 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.renderer.sublayers;
import java.util.ArrayList;
import org.oscim.utils.GlUtils;
@ -26,17 +25,16 @@ import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;
/**
* @author Hannes Janetzek
*/
// FIXME
public class TextureItem extends Inlist<TextureItem> {
private final static String TAG = TextureItem.class.getName();
// texture ID
public int id;
int width;
int height;
public int width;
public int height;
// vertex offset from which this texture is referenced
public short offset;
@ -45,13 +43,33 @@ public class TextureItem extends Inlist<TextureItem> {
// temporary Bitmap
public Bitmap bitmap;
// external bitmap (not from pool) use
// external bitmap (not from pool)
boolean ownBitmap;
// is only referencing a textureId, does not
// release the texture when TextureItem is
// released.
boolean isClone;
TextureItem(int id) {
this.id = id;
}
TextureItem(TextureItem ti) {
this.id = ti.id;
this.width = ti.width;
this.height = ti.height;
this.isClone = true;
}
public TextureItem(Bitmap bitmap) {
this.bitmap = bitmap;
this.id = -1;
this.ownBitmap = true;
this.width = bitmap.getWidth();
this.height = bitmap.getHeight();
}
public synchronized static void releaseAll(TextureItem ti) {
pool.releaseAll(ti);
}
@ -80,6 +98,7 @@ public class TextureItem extends Inlist<TextureItem> {
@Override
public void init(int num) {
int[] textureIds = new int[num];
GLES20.glGenTextures(num, textureIds, 0);
@ -103,6 +122,14 @@ public class TextureItem extends Inlist<TextureItem> {
if (it.ownBitmap)
return;
if (it.isClone){
it.isClone = false;
it.id = -1;
it.width = -1;
it.height = -1;
return;
}
releaseBitmap(it);
}
@ -110,7 +137,9 @@ public class TextureItem extends Inlist<TextureItem> {
protected void freeItem(TextureItem it) {
it.width = -1;
it.height = -1;
releaseTexture(it);
if (!it.isClone)
releaseTexture(it);
}
};
@ -125,6 +154,7 @@ public class TextureItem extends Inlist<TextureItem> {
private static int mTexCnt = 0;
static void releaseTexture(TextureItem it) {
synchronized (mTextures) {
if (it.id >= 0) {
mTextures.add(Integer.valueOf(it.id));

View File

@ -16,10 +16,6 @@ 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;
@ -42,4 +38,41 @@ public abstract class TextureLayer extends Layer {
}
abstract public boolean prepare();
static void putSprite(short buf[], int pos,
short tx, short ty,
short x1, short y1,
short x2, short y2,
short u1, short v1,
short u2, short v2) {
// top-left
buf[pos + 0] = tx;
buf[pos + 1] = ty;
buf[pos + 2] = x1;
buf[pos + 3] = y1;
buf[pos + 4] = u1;
buf[pos + 5] = v2;
// bot-left
buf[pos + 6] = tx;
buf[pos + 7] = ty;
buf[pos + 8] = x1;
buf[pos + 9] = y2;
buf[pos + 10] = u1;
buf[pos + 11] = v1;
// top-right
buf[pos + 12] = tx;
buf[pos + 13] = ty;
buf[pos + 14] = x2;
buf[pos + 15] = y1;
buf[pos + 16] = u2;
buf[pos + 17] = v2;
// bot-right
buf[pos + 18] = tx;
buf[pos + 19] = ty;
buf[pos + 20] = x2;
buf[pos + 21] = y2;
buf[pos + 22] = u2;
buf[pos + 23] = v1;
}
}

View File

@ -110,9 +110,6 @@ public final class TextureRenderer {
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 = ""
@ -125,7 +122,6 @@ public final class TextureRenderer {
+ "uniform float u_swidth;"
+ "uniform vec2 u_div;"
+ "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;"