refactor: TextureItem:
- use different pools for TextLayer and bitmap tiles to always get the correct (matching) texture from pool. - the common TextureItem pool is only used to provide the same api, it does not keep images or textures
This commit is contained in:
parent
fa2d3dd7a4
commit
eff5935068
@ -20,9 +20,14 @@ import org.oscim.backend.CanvasAdapter;
|
||||
import org.oscim.backend.canvas.Canvas;
|
||||
import org.oscim.renderer.atlas.TextureAtlas.Rect;
|
||||
import org.oscim.renderer.elements.TextureItem;
|
||||
import org.oscim.renderer.elements.TextureItem.TexturePool;
|
||||
import org.oscim.utils.pool.Inlist;
|
||||
|
||||
/**
|
||||
* UNUSED
|
||||
* */
|
||||
public abstract class SpriteManager<T> {
|
||||
TexturePool pool;
|
||||
|
||||
public class Sprite extends Inlist<Sprite> {
|
||||
|
||||
@ -46,14 +51,11 @@ public abstract class SpriteManager<T> {
|
||||
protected TextureItem mTexture;
|
||||
|
||||
public SpriteManager() {
|
||||
mTexture = TextureItem.get();
|
||||
mTexture = pool.get();
|
||||
|
||||
//mTexture.ownBitmap = true;
|
||||
|
||||
mAtlas = new TextureAtlas(
|
||||
TextureItem.TEXTURE_WIDTH,
|
||||
TextureItem.TEXTURE_HEIGHT,
|
||||
32);
|
||||
mAtlas = new TextureAtlas(256, 256, 32);
|
||||
|
||||
mCanvas.setBitmap(mTexture.bitmap);
|
||||
}
|
||||
@ -68,12 +70,12 @@ public abstract class SpriteManager<T> {
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mTexture = TextureItem.pool.releaseAll(mTexture);
|
||||
for (TextureItem t = mTexture; t != null; t = t.dispose());
|
||||
mAtlas.clear();
|
||||
items = null;
|
||||
|
||||
//mTexture.bitmap.eraseColor(Color.TRANSPARENT);
|
||||
mTexture = TextureItem.get();
|
||||
mTexture = pool.get();
|
||||
mCanvas.setBitmap(mTexture.bitmap);
|
||||
}
|
||||
|
||||
|
||||
@ -29,15 +29,17 @@ import org.oscim.renderer.MapRenderer.Matrices;
|
||||
* Renderer for a single bitmap, width and height must be power of 2.
|
||||
*/
|
||||
public class BitmapLayer extends TextureLayer {
|
||||
// TODO share layers.vbo() between BitmapTileLayers
|
||||
|
||||
// static final Logger log = LoggerFactory.getLogger(BitmapLayer.class);
|
||||
private Bitmap mBitmap;
|
||||
private final boolean mReuseBitmap;
|
||||
private final short[] mVertices;
|
||||
private int mWidth, mHeight;
|
||||
|
||||
/**
|
||||
* @param reuseBitmap false if the Bitmap should be recycled after
|
||||
* it is compiled to texture.
|
||||
* @param reuseBitmap false if the Bitmap should be disposed
|
||||
* after loading to texture.
|
||||
*/
|
||||
public BitmapLayer(boolean reuseBitmap) {
|
||||
super(RenderElement.BITMAP);
|
||||
@ -49,26 +51,19 @@ public class BitmapLayer extends TextureLayer {
|
||||
verticesCnt = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* w/h sets also target dimension to render the bitmap.
|
||||
*/
|
||||
public void setBitmap(Bitmap bitmap, int w, int h) {
|
||||
mWidth = w;
|
||||
mHeight = h;
|
||||
|
||||
mBitmap = bitmap;
|
||||
if (this.textures == null)
|
||||
this.textures = new TextureItem(mBitmap);
|
||||
if (textures == null)
|
||||
textures = new TextureItem(mBitmap);
|
||||
|
||||
TextureItem ti = this.textures;
|
||||
ti.vertices = TextureLayer.Renderer.INDICES_PER_SPRITE;
|
||||
}
|
||||
|
||||
private int mWidth, mHeight;
|
||||
|
||||
/**
|
||||
* Set target dimension to renderthe bitmap
|
||||
*/
|
||||
public void setSize(int w, int h) {
|
||||
mWidth = w;
|
||||
mHeight = h;
|
||||
TextureItem t = textures;
|
||||
t.vertices = TextureLayer.INDICES_PER_SPRITE;
|
||||
}
|
||||
|
||||
private void setVertices(ShortBuffer sbuf) {
|
||||
@ -76,37 +71,40 @@ public class BitmapLayer extends TextureLayer {
|
||||
short w = (short) (mWidth * MapRenderer.COORD_SCALE);
|
||||
short h = (short) (mHeight * MapRenderer.COORD_SCALE);
|
||||
|
||||
short t = 1;
|
||||
short texMin = 0;
|
||||
short texMax = 1;
|
||||
|
||||
// putSprite(buf, pos, tx, ty, x1, y1, x2, y2, u1, v1, u2, v2);
|
||||
int pos = 0;
|
||||
|
||||
// top-left
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = texMin;
|
||||
buf[pos++] = texMin;
|
||||
// bot-left
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = h;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = t;
|
||||
buf[pos++] = texMin;
|
||||
buf[pos++] = texMax;
|
||||
// top-right
|
||||
buf[pos++] = w;
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = t;
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = texMax;
|
||||
buf[pos++] = texMin;
|
||||
// bot-right
|
||||
buf[pos++] = w;
|
||||
buf[pos++] = h;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = -1;
|
||||
buf[pos++] = t;
|
||||
buf[pos++] = t;
|
||||
buf[pos++] = texMax;
|
||||
buf[pos++] = texMax;
|
||||
|
||||
this.offset = sbuf.position() * 2; // bytes
|
||||
sbuf.put(buf);
|
||||
@ -137,26 +135,25 @@ public class BitmapLayer extends TextureLayer {
|
||||
@Override
|
||||
protected void clear() {
|
||||
|
||||
if (mBitmap != null) {
|
||||
if (!mReuseBitmap)
|
||||
mBitmap.recycle();
|
||||
// release textures and vertexItems
|
||||
super.clear();
|
||||
|
||||
mBitmap = null;
|
||||
textures.bitmap = null;
|
||||
}
|
||||
if (mBitmap == null)
|
||||
return;
|
||||
|
||||
TextureItem.releaseTexture(textures);
|
||||
textures = null;
|
||||
if (!mReuseBitmap)
|
||||
mBitmap.recycle();
|
||||
|
||||
vertexItems = VertexItem.pool.releaseAll(vertexItems);
|
||||
mBitmap = null;
|
||||
|
||||
//textures.bitmap = null;
|
||||
//textures.dispose();
|
||||
//TextureItem.pool.releaseTexture(textures);
|
||||
//textures = null;
|
||||
}
|
||||
|
||||
public static final class Renderer {
|
||||
|
||||
//static final Logger log = LoggerFactory.getLogger(BitmapRenderer.class);
|
||||
|
||||
public final static boolean debug = true;
|
||||
|
||||
private static int mTextureProgram;
|
||||
private static int hTextureMVMatrix;
|
||||
private static int hTextureProjMatrix;
|
||||
@ -209,16 +206,16 @@ public class BitmapLayer extends TextureLayer {
|
||||
|
||||
MapRenderer.bindQuadIndicesVBO(true);
|
||||
|
||||
for (TextureItem ti = tl.textures; ti != null; ti = ti.next) {
|
||||
for (TextureItem t = tl.textures; t != null; t = t.next) {
|
||||
|
||||
ti.bind();
|
||||
t.bind();
|
||||
|
||||
int maxVertices = MapRenderer.maxQuads * INDICES_PER_SPRITE;
|
||||
|
||||
// draw up to maxVertices in each iteration
|
||||
for (int i = 0; i < ti.vertices; i += maxVertices) {
|
||||
for (int i = 0; i < t.vertices; i += maxVertices) {
|
||||
// to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8)
|
||||
int off = (ti.offset + i) * 8 + tl.offset;
|
||||
int off = (t.offset + i) * 8 + tl.offset;
|
||||
|
||||
GL.glVertexAttribPointer(hTextureVertex, 4,
|
||||
GL20.GL_SHORT, false, 12, off);
|
||||
@ -226,7 +223,7 @@ public class BitmapLayer extends TextureLayer {
|
||||
GL.glVertexAttribPointer(hTextureTexCoord, 2,
|
||||
GL20.GL_SHORT, false, 12, off + 8);
|
||||
|
||||
int numVertices = ti.vertices - i;
|
||||
int numVertices = t.vertices - i;
|
||||
if (numVertices > maxVertices)
|
||||
numVertices = maxVertices;
|
||||
|
||||
@ -245,9 +242,6 @@ public class BitmapLayer extends TextureLayer {
|
||||
+ "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;"
|
||||
+ "void main() {"
|
||||
+ " gl_Position = u_mv * vec4(vertex.xy, 0.0, 1.0);"
|
||||
|
||||
@ -38,7 +38,7 @@ public class ElementLayers {
|
||||
BitmapLayer.Renderer.init();
|
||||
MeshLayer.Renderer.init();
|
||||
|
||||
TextureItem.init(gl, 0);
|
||||
TextureItem.init(gl);
|
||||
}
|
||||
|
||||
/** mixed Polygon- and LineLayer */
|
||||
|
||||
@ -73,7 +73,7 @@ public final class SymbolLayer extends TextureLayer {
|
||||
|
||||
prevTextures = textures;
|
||||
textures = null;
|
||||
TextureItem to = null;
|
||||
TextureItem t = null;
|
||||
|
||||
for (SymbolItem it = symbols; it != null;) {
|
||||
int width = 0, height = 0;
|
||||
@ -82,14 +82,13 @@ public final class SymbolLayer extends TextureLayer {
|
||||
|
||||
if (it.texRegion != null) {
|
||||
|
||||
// FIXME this work only with one TextureAtlas per
|
||||
// SymbolLayer.
|
||||
// FIXME this work only with one TextureAtlas per SymbolLayer.
|
||||
if (textures == null) {
|
||||
to = it.texRegion.atlas.loadTexture();
|
||||
t = it.texRegion.atlas.loadTexture();
|
||||
// clone TextureItem to use same texID with
|
||||
// multiple TextureItem
|
||||
to = TextureItem.clone(to);
|
||||
textures = Inlist.appendItem(textures, to);
|
||||
t = TextureItem.clone(t);
|
||||
textures = Inlist.appendItem(textures, t);
|
||||
}
|
||||
|
||||
TextureAtlas.Rect r = it.texRegion.rect;
|
||||
@ -99,20 +98,20 @@ public final class SymbolLayer extends TextureLayer {
|
||||
height = r.h;
|
||||
|
||||
} else if (it.bitmap != null) {
|
||||
width = it.bitmap.getWidth();
|
||||
height = it.bitmap.getHeight();
|
||||
to = getTexture(it.bitmap);
|
||||
if (to == null) {
|
||||
to = new TextureItem(it.bitmap);
|
||||
textures = Inlist.appendItem(textures, to);
|
||||
t = getTexture(it.bitmap);
|
||||
|
||||
to.upload();
|
||||
if (t == null) {
|
||||
t = new TextureItem(it.bitmap);
|
||||
textures = Inlist.appendItem(textures, t);
|
||||
t.upload();
|
||||
|
||||
t.offset = numIndices;
|
||||
t.vertices = 0;
|
||||
}
|
||||
to.offset = numIndices;
|
||||
to.vertices = 0;
|
||||
}
|
||||
width = t.width;
|
||||
height = t.height;
|
||||
|
||||
if (to == null) {
|
||||
} else { //if (to == null) {
|
||||
log.debug("Bad SymbolItem");
|
||||
continue;
|
||||
}
|
||||
@ -126,9 +125,15 @@ public final class SymbolLayer extends TextureLayer {
|
||||
short x1 = 0, y1 = 0, x2 = 0, y2 = 0;
|
||||
|
||||
// add symbol items referencing the same bitmap /
|
||||
for (SymbolItem it2 = it;; it2 = it2.next) {
|
||||
for (SymbolItem prev = it; it != null; it = it.next) {
|
||||
|
||||
if (it == it2 || it.offset != prevOffset) {
|
||||
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;
|
||||
@ -147,18 +152,12 @@ public final class SymbolLayer extends TextureLayer {
|
||||
y2 = (short) (SCALE * (-hh));
|
||||
}
|
||||
}
|
||||
if (it2 == null
|
||||
|| (it.bitmap != null && it2.bitmap != it.bitmap)
|
||||
|| (it.texRegion != null && it2.texRegion != it.texRegion)) {
|
||||
it = it2;
|
||||
break;
|
||||
}
|
||||
|
||||
// add vertices
|
||||
short tx = (short) ((int) (SCALE * it2.x) & LBIT_MASK
|
||||
| (it2.billboard ? 1 : 0));
|
||||
short tx = (short) ((int) (SCALE * it.x) & LBIT_MASK
|
||||
| (it.billboard ? 1 : 0));
|
||||
|
||||
short ty = (short) (SCALE * it2.y);
|
||||
short ty = (short) (SCALE * it.y);
|
||||
|
||||
if (pos == VertexItem.SIZE) {
|
||||
sbuf.put(buf, 0, VertexItem.SIZE);
|
||||
@ -168,14 +167,12 @@ public final class SymbolLayer extends TextureLayer {
|
||||
TextureLayer.putSprite(buf, pos, tx, ty,
|
||||
x1, y1, x2, y2, u1, v1, u2, v2);
|
||||
|
||||
// TextureRenderer.VERTICES_PER_SPRITE
|
||||
// * TextureRenderer.SHORTS_PER_VERTICE;
|
||||
pos += 24;
|
||||
pos += TextLayer.VERTICES_PER_SPRITE * 6;
|
||||
|
||||
// six elements used to draw the four vertices
|
||||
to.vertices += TextureLayer.Renderer.INDICES_PER_SPRITE;
|
||||
t.vertices += TextureLayer.INDICES_PER_SPRITE;
|
||||
}
|
||||
numIndices += to.vertices;
|
||||
numIndices += t.vertices;
|
||||
}
|
||||
|
||||
if (pos > 0)
|
||||
@ -183,35 +180,40 @@ public final class SymbolLayer extends TextureLayer {
|
||||
|
||||
si = VertexItem.pool.release(si);
|
||||
|
||||
prevTextures = TextureItem.pool.releaseAll(prevTextures);
|
||||
for (t = prevTextures; t != null; t = t.dispose());
|
||||
prevTextures = null;
|
||||
}
|
||||
|
||||
private TextureItem getTexture(Bitmap bitmap) {
|
||||
TextureItem to;
|
||||
TextureItem t;
|
||||
|
||||
for (to = prevTextures; to != null; to = to.next) {
|
||||
if (to.bitmap == bitmap) {
|
||||
prevTextures = Inlist.remove(prevTextures, to);
|
||||
textures = Inlist.appendItem(textures, to);
|
||||
break;
|
||||
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 to;
|
||||
return null;
|
||||
}
|
||||
|
||||
public void clearItems() {
|
||||
symbols = SymbolItem.pool.releaseAll(symbols);
|
||||
verticesCnt = 0;
|
||||
//verticesCnt = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
textures = TextureItem.pool.releaseAll(textures);
|
||||
symbols = SymbolItem.pool.releaseAll(symbols);
|
||||
vertexItems = VertexItem.pool.releaseAll(vertexItems);
|
||||
// release textures
|
||||
super.clear();
|
||||
clearItems();
|
||||
|
||||
verticesCnt = 0;
|
||||
//symbols = SymbolItem.pool.releaseAll(symbols);
|
||||
//vertexItems = VertexItem.pool.releaseAll(vertexItems);
|
||||
//verticesCnt = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -17,14 +17,11 @@
|
||||
package org.oscim.renderer.elements;
|
||||
|
||||
import static org.oscim.renderer.MapRenderer.COORD_SCALE;
|
||||
import static org.oscim.renderer.elements.TextureItem.TEXTURE_HEIGHT;
|
||||
import static org.oscim.renderer.elements.TextureItem.TEXTURE_WIDTH;
|
||||
|
||||
import org.oscim.backend.CanvasAdapter;
|
||||
import org.oscim.backend.canvas.Canvas;
|
||||
|
||||
public final class TextLayer extends TextureLayer {
|
||||
|
||||
//static final Logger log = LoggerFactory.getLogger(TextureLayer.class);
|
||||
|
||||
private final static int LBIT_MASK = 0xfffffffe;
|
||||
@ -94,15 +91,18 @@ public final class TextLayer extends TextureLayer {
|
||||
float y = 0;
|
||||
float yy;
|
||||
|
||||
TextureItem to = TextureItem.get();
|
||||
textures = to;
|
||||
mCanvas.setBitmap(to.bitmap);
|
||||
TextureItem t = pool.get();
|
||||
textures = t;
|
||||
mCanvas.setBitmap(t.bitmap);
|
||||
|
||||
for (TextItem it = labels; it != null;) {
|
||||
|
||||
float width = it.width + 2 * mFontPadX;
|
||||
float height = (int) (it.text.fontHeight) + 0.5f;
|
||||
|
||||
if (height > TEXTURE_HEIGHT)
|
||||
height = TEXTURE_HEIGHT;
|
||||
|
||||
if (height > advanceY)
|
||||
advanceY = (int) height;
|
||||
|
||||
@ -112,14 +112,14 @@ public final class TextLayer extends TextureLayer {
|
||||
advanceY = (int) (height + 0.5f);
|
||||
|
||||
if (y + height > TEXTURE_HEIGHT) {
|
||||
to.offset = offsetIndices;
|
||||
to.vertices = (short) (numIndices - offsetIndices);
|
||||
t.offset = offsetIndices;
|
||||
t.vertices = (short) (numIndices - offsetIndices);
|
||||
offsetIndices = numIndices;
|
||||
|
||||
to.next = TextureItem.get();
|
||||
to = to.next;
|
||||
t.next = pool.get();
|
||||
t = t.next;
|
||||
|
||||
mCanvas.setBitmap(to.bitmap);
|
||||
mCanvas.setBitmap(t.bitmap);
|
||||
|
||||
x = 0;
|
||||
y = 0;
|
||||
@ -246,8 +246,8 @@ public final class TextLayer extends TextureLayer {
|
||||
buf[pos++] = v1;
|
||||
|
||||
// six indices to draw the four vertices
|
||||
numIndices += TextureLayer.Renderer.INDICES_PER_SPRITE;
|
||||
verticesCnt += 4;
|
||||
numIndices += TextureLayer.INDICES_PER_SPRITE;
|
||||
|
||||
if (it.next == null || (it.next.text != it.text)
|
||||
|| (it.next.string != it.string)) {
|
||||
@ -262,18 +262,21 @@ public final class TextLayer extends TextureLayer {
|
||||
|
||||
vi.used = pos;
|
||||
|
||||
to.offset = offsetIndices;
|
||||
to.vertices = (short) (numIndices - offsetIndices);
|
||||
t.offset = offsetIndices;
|
||||
t.vertices = (short) (numIndices - offsetIndices);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
textures = TextureItem.pool.releaseAll(textures);
|
||||
labels = TextItem.pool.releaseAll(labels);
|
||||
vertexItems = VertexItem.pool.releaseAll(vertexItems);
|
||||
verticesCnt = 0;
|
||||
// release textures
|
||||
super.clear();
|
||||
|
||||
clearLabels();
|
||||
//labels = TextItem.pool.releaseAll(labels);
|
||||
//vertexItems = VertexItem.pool.releaseAll(vertexItems);
|
||||
//verticesCnt = 0;
|
||||
}
|
||||
|
||||
public void clearLabels() {
|
||||
|
||||
@ -18,6 +18,8 @@ package org.oscim.renderer.elements;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
|
||||
import org.oscim.backend.CanvasAdapter;
|
||||
import org.oscim.backend.GL20;
|
||||
import org.oscim.backend.canvas.Bitmap;
|
||||
@ -29,19 +31,16 @@ import org.oscim.utils.pool.SyncPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
// TODO use separate pools for different bitmap types and dimensions
|
||||
|
||||
public class TextureItem extends Inlist<TextureItem> {
|
||||
static final Logger log = LoggerFactory.getLogger(TextureItem.class);
|
||||
|
||||
private static GL20 GL;
|
||||
|
||||
/** texture ID */
|
||||
public int id;
|
||||
|
||||
public int width;
|
||||
public int height;
|
||||
public boolean repeat;
|
||||
/** current settings */
|
||||
public final int width;
|
||||
public final int height;
|
||||
public final boolean repeat;
|
||||
|
||||
/** vertex offset from which this texture is referenced */
|
||||
public short offset;
|
||||
@ -50,272 +49,290 @@ public class TextureItem extends Inlist<TextureItem> {
|
||||
/** temporary Bitmap */
|
||||
public Bitmap bitmap;
|
||||
|
||||
/** external bitmap (not from pool) */
|
||||
private boolean ownBitmap;
|
||||
|
||||
/** do not release the texture when TextureItem is released. */
|
||||
private boolean isClone;
|
||||
private boolean ref;
|
||||
|
||||
/** texture data is ready */
|
||||
private boolean isReady;
|
||||
private boolean ready;
|
||||
|
||||
private TextureItem(int id) {
|
||||
final TexturePool pool;
|
||||
|
||||
private TextureItem(TexturePool pool, int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static TextureItem clone(TextureItem ti) {
|
||||
TextureItem clone = new TextureItem(ti.id);
|
||||
clone.id = ti.id;
|
||||
clone.width = ti.width;
|
||||
clone.height = ti.height;
|
||||
clone.isClone = true;
|
||||
// original texture needs to be loaded
|
||||
clone.isReady = true;
|
||||
return clone;
|
||||
this.width = pool.mWidth;
|
||||
this.height = pool.mHeight;
|
||||
this.pool = pool;
|
||||
this.repeat = false;
|
||||
}
|
||||
|
||||
public TextureItem(Bitmap bitmap) {
|
||||
this.bitmap = bitmap;
|
||||
this.id = -1;
|
||||
this.ownBitmap = true;
|
||||
this.width = bitmap.getWidth();
|
||||
this.height = bitmap.getHeight();
|
||||
this.pool = NOPOOL;
|
||||
this.repeat = false;
|
||||
|
||||
}
|
||||
|
||||
public TextureItem(Bitmap bitmap, boolean repeat) {
|
||||
this.bitmap = bitmap;
|
||||
this.id = -1;
|
||||
this.ownBitmap = true;
|
||||
this.width = bitmap.getWidth();
|
||||
this.height = bitmap.getHeight();
|
||||
this.repeat = repeat;
|
||||
this.pool = NOPOOL;
|
||||
|
||||
}
|
||||
|
||||
private TextureItem(TexturePool pool, int id, int width, int height) {
|
||||
this.id = id;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.pool = pool;
|
||||
this.repeat = false;
|
||||
}
|
||||
|
||||
public static TextureItem clone(TextureItem ti) {
|
||||
// original texture needs to be loaded
|
||||
if (!ti.ready)
|
||||
throw new IllegalStateException();
|
||||
|
||||
TextureItem clone = new TextureItem(ti.pool, ti.id, ti.width, ti.height);
|
||||
clone.id = ti.id;
|
||||
clone.ref = true;
|
||||
clone.ready = true;
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload Image to Texture
|
||||
* [on GL-Thread]
|
||||
*/
|
||||
public void upload() {
|
||||
if (!isReady) {
|
||||
TextureItem.uploadTexture(this);
|
||||
isReady = true;
|
||||
if (!ready) {
|
||||
pool.uploadTexture(this);
|
||||
ready = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind Texture for rendering
|
||||
* [on GL-Thread]
|
||||
*/
|
||||
public void bind() {
|
||||
if (!isReady) {
|
||||
TextureItem.uploadTexture(this);
|
||||
isReady = true;
|
||||
if (!ready) {
|
||||
pool.uploadTexture(this);
|
||||
ready = true;
|
||||
} else {
|
||||
GLState.bindTex2D(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a TextureItem from pool with default Bitmap with dimension
|
||||
* TextureRenderer.TEXTURE_WIDTH/HEIGHT.
|
||||
* Dispose TextureItem
|
||||
* [Threadsafe]
|
||||
*
|
||||
* @return this.next
|
||||
*/
|
||||
public synchronized static TextureItem get() {
|
||||
TextureItem ti = pool.get();
|
||||
ti.bitmap = getBitmap();
|
||||
ti.bitmap.eraseColor(Color.TRANSPARENT);
|
||||
|
||||
return ti;
|
||||
@CheckReturnValue
|
||||
public TextureItem dispose() {
|
||||
TextureItem n = this.next;
|
||||
this.next = null;
|
||||
pool.release(this);
|
||||
return n;
|
||||
}
|
||||
|
||||
static class TextureItemPool extends SyncPool<TextureItem> {
|
||||
public static class TexturePool extends SyncPool<TextureItem> {
|
||||
|
||||
public TextureItemPool() {
|
||||
super(10);
|
||||
private final ArrayList<Integer> mTexDisposed = new ArrayList<Integer>();
|
||||
private final ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(10);
|
||||
|
||||
private final int mHeight;
|
||||
private final int mWidth;
|
||||
//private final int mBitmapFormat;
|
||||
//private final int mBitmapType;
|
||||
|
||||
protected int mTexCnt = 0;
|
||||
|
||||
public TexturePool(int maxFill, int width, int height) {
|
||||
super(maxFill);
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(int num) {
|
||||
if (pool != null) {
|
||||
log.debug("still textures in pool! " + fill);
|
||||
pool = null;
|
||||
}
|
||||
public TextureItem releaseAll(TextureItem t) {
|
||||
throw new RuntimeException("use TextureItem.dispose()");
|
||||
}
|
||||
|
||||
if (num > 0) {
|
||||
int[] textureIds = GLUtils.glGenTextures(num);
|
||||
for (int i = 0; i < num; i++) {
|
||||
TextureItem to = new TextureItem(textureIds[i]);
|
||||
initTexture(to);
|
||||
pool = Inlist.push(pool, to);
|
||||
/**
|
||||
* Retrieve a TextureItem from pool.
|
||||
*/
|
||||
public synchronized TextureItem get() {
|
||||
TextureItem t = super.get();
|
||||
|
||||
synchronized (mBitmaps) {
|
||||
int size = mBitmaps.size();
|
||||
if (size == 0)
|
||||
t.bitmap = CanvasAdapter.g.getBitmap(mWidth, mHeight, 0);
|
||||
else {
|
||||
t.bitmap = mBitmaps.remove(size - 1);
|
||||
t.bitmap.eraseColor(Color.TRANSPARENT);
|
||||
}
|
||||
}
|
||||
|
||||
fill = num;
|
||||
}
|
||||
|
||||
public TextureItem get(int width, int height) {
|
||||
return null;
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TextureItem createItem() {
|
||||
return new TextureItem(-1);
|
||||
return new TextureItem(this, -1);
|
||||
}
|
||||
|
||||
/** called when item is added back to pool */
|
||||
@Override
|
||||
protected boolean clearItem(TextureItem t) {
|
||||
|
||||
if (t.ownBitmap) {
|
||||
t.bitmap = null;
|
||||
t.ownBitmap = false;
|
||||
releaseTexture(t);
|
||||
//if (t.ownBitmap) {
|
||||
// t.bitmap = null;
|
||||
// t.ownBitmap = false;
|
||||
// releaseTexture(t);
|
||||
// return false;
|
||||
//}
|
||||
|
||||
if (t.ref)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t.isClone) {
|
||||
t.isClone = false;
|
||||
t.id = -1;
|
||||
t.width = -1;
|
||||
t.height = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
t.isReady = false;
|
||||
|
||||
t.ready = false;
|
||||
releaseBitmap(t);
|
||||
|
||||
return true;
|
||||
// only add back to pool when a texture
|
||||
// is already assigned
|
||||
return t.id >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void freeItem(TextureItem t) {
|
||||
t.width = -1;
|
||||
t.height = -1;
|
||||
|
||||
if (!t.isClone)
|
||||
releaseTexture(t);
|
||||
if (!t.ref) {
|
||||
synchronized (mTexDisposed) {
|
||||
if (t.id >= 0) {
|
||||
mTexDisposed.add(Integer.valueOf(t.id));
|
||||
t.id = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void releaseBitmap(TextureItem t) {
|
||||
|
||||
if (t.bitmap == null)
|
||||
return;
|
||||
|
||||
synchronized (mBitmaps) {
|
||||
mBitmaps.add(t.bitmap);
|
||||
t.bitmap = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadTexture(TextureItem t) {
|
||||
|
||||
if (t.bitmap == null)
|
||||
throw new RuntimeException("Missing bitmap for texture");
|
||||
|
||||
synchronized (mTexDisposed) {
|
||||
int size = mTexDisposed.size();
|
||||
if (size > 0) {
|
||||
int[] tmp = new int[size];
|
||||
for (int i = 0; i < size; i++)
|
||||
tmp[i] = mTexDisposed.get(i).intValue();
|
||||
|
||||
mTexDisposed.clear();
|
||||
GLUtils.glDeleteTextures(size, tmp);
|
||||
mTexCnt -= size;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.id < 0) {
|
||||
int[] textureIds = GLUtils.glGenTextures(1);
|
||||
t.id = textureIds[0];
|
||||
|
||||
initTexture(t);
|
||||
|
||||
if (TextureLayer.Renderer.debug)
|
||||
log.debug("fill:" + getFill()
|
||||
+ " count:" + mTexCnt
|
||||
+ " new texture " + t.id);
|
||||
|
||||
mTexCnt++;
|
||||
|
||||
t.bitmap.uploadToTexture(false);
|
||||
} else {
|
||||
GLState.bindTex2D(t.id);
|
||||
// use faster subimage upload
|
||||
t.bitmap.uploadToTexture(true);
|
||||
}
|
||||
|
||||
//if (t.ownBitmap) {
|
||||
// t.bitmap.uploadToTexture(false);
|
||||
//} else
|
||||
|
||||
//if (t.width == mWidth && t.height == mHeight) {
|
||||
// // use faster subimage upload
|
||||
// t.bitmap.uploadToTexture(true);
|
||||
//} else {
|
||||
// t.bitmap.uploadToTexture(false);
|
||||
//}
|
||||
|
||||
if (TextureLayer.Renderer.debug)
|
||||
GLUtils.checkGlError(TextureItem.class.getName());
|
||||
|
||||
releaseBitmap(t);
|
||||
}
|
||||
|
||||
protected void initTexture(TextureItem t) {
|
||||
GLState.bindTex2D(t.id);
|
||||
|
||||
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MIN_FILTER,
|
||||
GL20.GL_LINEAR);
|
||||
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAG_FILTER,
|
||||
GL20.GL_LINEAR);
|
||||
|
||||
if (t.repeat) {
|
||||
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_S,
|
||||
GL20.GL_REPEAT);
|
||||
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_T,
|
||||
GL20.GL_REPEAT);
|
||||
} else {
|
||||
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_S,
|
||||
GL20.GL_CLAMP_TO_EDGE);
|
||||
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_T,
|
||||
GL20.GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public final static SyncPool<TextureItem> pool = new TextureItemPool();
|
||||
// Pool for not-pooled textures. Disposed items will only be released
|
||||
// on the GL-Thread and will not be put back in any pool.
|
||||
final static TexturePool NOPOOL = new TexturePool(0, 0, 0) {
|
||||
protected void releaseBitmap(TextureItem t) {
|
||||
// TODO
|
||||
};
|
||||
};
|
||||
|
||||
private final static ArrayList<Integer> mTextures = new ArrayList<Integer>();
|
||||
private final static ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(10);
|
||||
// public final static TexturePool nopool(){
|
||||
// return NOPOOL;
|
||||
// }
|
||||
|
||||
public final static int TEXTURE_WIDTH = 512;
|
||||
public final static int TEXTURE_HEIGHT = 256;
|
||||
private static GL20 GL;
|
||||
|
||||
//private static int mBitmapFormat;
|
||||
//private static int mBitmapType;
|
||||
private static int mTexCnt = 0;
|
||||
|
||||
static void releaseTexture(TextureItem it) {
|
||||
|
||||
synchronized (mTextures) {
|
||||
if (it.id >= 0) {
|
||||
mTextures.add(Integer.valueOf(it.id));
|
||||
it.id = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function may only be used in GLRenderer Thread.
|
||||
*
|
||||
* @param t
|
||||
* the TextureObjet to compile and upload
|
||||
*/
|
||||
private static void uploadTexture(TextureItem t) {
|
||||
GL.glBindTexture(GL20.GL_TEXTURE_2D, 0);
|
||||
if (t.bitmap == null) {
|
||||
throw new RuntimeException("Missing bitmap for texture");
|
||||
}
|
||||
|
||||
// free unused textures -> TODO find a better place for this
|
||||
synchronized (mTextures) {
|
||||
int size = mTextures.size();
|
||||
if (size > 0) {
|
||||
int[] tmp = new int[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
tmp[i] = mTextures.get(i).intValue();
|
||||
}
|
||||
mTextures.clear();
|
||||
GLUtils.glDeleteTextures(size, tmp);
|
||||
|
||||
mTexCnt -= size;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.id < 0) {
|
||||
mTexCnt++;
|
||||
int[] textureIds = GLUtils.glGenTextures(1);
|
||||
t.id = textureIds[0];
|
||||
initTexture(t);
|
||||
if (TextureLayer.Renderer.debug)
|
||||
log.debug("fill:" + pool.getFill()
|
||||
+ " count:" + mTexCnt
|
||||
+ " new texture " + t.id);
|
||||
}
|
||||
|
||||
GLState.bindTex2D(t.id);
|
||||
|
||||
if (t.ownBitmap) {
|
||||
t.bitmap.uploadToTexture(false);
|
||||
} else if (t.width == TEXTURE_WIDTH && t.height == TEXTURE_HEIGHT) {
|
||||
t.bitmap.uploadToTexture(true);
|
||||
} else {
|
||||
t.bitmap.uploadToTexture(false);
|
||||
t.width = TEXTURE_WIDTH;
|
||||
t.height = TEXTURE_HEIGHT;
|
||||
}
|
||||
|
||||
if (TextureLayer.Renderer.debug)
|
||||
GLUtils.checkGlError(TextureItem.class.getName());
|
||||
|
||||
if (!t.ownBitmap)
|
||||
TextureItem.releaseBitmap(t);
|
||||
}
|
||||
|
||||
private static void initTexture(TextureItem t) {
|
||||
GLState.bindTex2D(t.id);
|
||||
|
||||
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MIN_FILTER,
|
||||
GL20.GL_LINEAR);
|
||||
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAG_FILTER,
|
||||
GL20.GL_LINEAR);
|
||||
|
||||
if (t.repeat) {
|
||||
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_S,
|
||||
GL20.GL_REPEAT);
|
||||
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_T,
|
||||
GL20.GL_REPEAT);
|
||||
} else {
|
||||
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_S,
|
||||
GL20.GL_CLAMP_TO_EDGE);
|
||||
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_T,
|
||||
GL20.GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
}
|
||||
|
||||
static void init(GL20 gl, int num) {
|
||||
static void init(GL20 gl) {
|
||||
GL = gl;
|
||||
|
||||
mTexCnt = num;
|
||||
pool.init(num);
|
||||
|
||||
mBitmaps.clear();
|
||||
mTextures.clear();
|
||||
}
|
||||
|
||||
static Bitmap getBitmap() {
|
||||
synchronized (mBitmaps) {
|
||||
int size = mBitmaps.size();
|
||||
if (size == 0) {
|
||||
return CanvasAdapter.g.getBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT, 0);
|
||||
}
|
||||
|
||||
return mBitmaps.remove(size - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void releaseBitmap(TextureItem it) {
|
||||
synchronized (mBitmaps) {
|
||||
if (it.bitmap != null) {
|
||||
mBitmaps.add(it.bitmap);
|
||||
it.bitmap = null;
|
||||
}
|
||||
}
|
||||
// mTexCnt = num;
|
||||
// NOPOOL.init(num);
|
||||
//
|
||||
// mBitmaps.clear();
|
||||
// mTexDisposed.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,28 +25,38 @@ import org.oscim.renderer.GLState;
|
||||
import org.oscim.renderer.GLUtils;
|
||||
import org.oscim.renderer.MapRenderer;
|
||||
import org.oscim.renderer.MapRenderer.Matrices;
|
||||
import org.oscim.renderer.elements.TextureItem.TexturePool;
|
||||
|
||||
public abstract class TextureLayer extends RenderElement {
|
||||
|
||||
public final static int INDICES_PER_SPRITE = 6;
|
||||
final static int VERTICES_PER_SPRITE = 4;
|
||||
final static int SHORTS_PER_VERTICE = 6;
|
||||
|
||||
final static int TEXTURE_HEIGHT = 128;
|
||||
final static int TEXTURE_WIDTH = 512;
|
||||
final static int POOL_FILL = 10;
|
||||
|
||||
/** pool shared by TextLayers */
|
||||
final static TexturePool pool = new TexturePool(POOL_FILL,
|
||||
TEXTURE_WIDTH,
|
||||
TEXTURE_HEIGHT);
|
||||
|
||||
protected TextureLayer(byte type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
// holds textures and offset in vbo
|
||||
/** holds textures and offset in vbo */
|
||||
public TextureItem textures;
|
||||
|
||||
// scale mode
|
||||
/** 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)
|
||||
to.upload();
|
||||
for (TextureItem t = textures; t != null; t = t.next)
|
||||
t.upload();
|
||||
|
||||
// add vertices to vbo
|
||||
ElementLayers.addPoolItems(this, sbuf);
|
||||
@ -54,6 +64,14 @@ public abstract class TextureLayer extends RenderElement {
|
||||
|
||||
abstract public boolean prepare();
|
||||
|
||||
protected void clear() {
|
||||
while (textures != null)
|
||||
textures = textures.dispose();
|
||||
|
||||
vertexItems = VertexItem.pool.releaseAll(vertexItems);
|
||||
verticesCnt = 0;
|
||||
}
|
||||
|
||||
static void putSprite(short buf[], int pos,
|
||||
short tx, short ty,
|
||||
short x1, short y1,
|
||||
@ -105,10 +123,6 @@ public abstract class TextureLayer extends RenderElement {
|
||||
private static int hTextureTexCoord;
|
||||
private static int hTextureSize;
|
||||
|
||||
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,
|
||||
@ -121,9 +135,12 @@ public abstract class TextureLayer extends RenderElement {
|
||||
hTextureScreenScale = GL.glGetUniformLocation(mTextureProgram, "u_swidth");
|
||||
hTextureVertex = GL.glGetAttribLocation(mTextureProgram, "vertex");
|
||||
hTextureTexCoord = GL.glGetAttribLocation(mTextureProgram, "tex_coord");
|
||||
|
||||
// FIXME pool should be disposed on exit...
|
||||
pool.init(0);
|
||||
}
|
||||
|
||||
public static RenderElement draw(RenderElement renderElement, float scale, Matrices m) {
|
||||
public static RenderElement draw(RenderElement l, float scale, Matrices m) {
|
||||
|
||||
GLState.test(false, false);
|
||||
GLState.blend(true);
|
||||
@ -132,7 +149,7 @@ public abstract class TextureLayer extends RenderElement {
|
||||
|
||||
GLState.enableVertexArrays(hTextureTexCoord, hTextureVertex);
|
||||
|
||||
TextureLayer tl = (TextureLayer) renderElement;
|
||||
TextureLayer tl = (TextureLayer) l;
|
||||
|
||||
if (tl.fixed)
|
||||
GL.glUniform1f(hTextureScale, (float) Math.sqrt(scale));
|
||||
@ -146,20 +163,18 @@ public abstract class TextureLayer extends RenderElement {
|
||||
|
||||
MapRenderer.bindQuadIndicesVBO(true);
|
||||
|
||||
for (TextureItem ti = tl.textures; ti != null; ti = ti.next) {
|
||||
|
||||
ti.bind();
|
||||
for (TextureItem t = tl.textures; t != null; t = t.next) {
|
||||
GL.glUniform2f(hTextureSize,
|
||||
1f / (t.width * COORD_SCALE),
|
||||
1f / (t.height * COORD_SCALE));
|
||||
t.bind();
|
||||
|
||||
int maxVertices = MapRenderer.maxQuads * INDICES_PER_SPRITE;
|
||||
|
||||
GL.glUniform2f(hTextureSize,
|
||||
1f / (ti.width * COORD_SCALE),
|
||||
1f / (ti.height * COORD_SCALE));
|
||||
|
||||
// draw up to maxVertices in each iteration
|
||||
for (int i = 0; i < ti.vertices; i += maxVertices) {
|
||||
for (int i = 0; i < t.vertices; i += maxVertices) {
|
||||
// to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8)
|
||||
int off = (ti.offset + i) * 8 + tl.offset;
|
||||
int off = (t.offset + i) * 8 + tl.offset;
|
||||
|
||||
GL.glVertexAttribPointer(hTextureVertex, 4,
|
||||
GL20.GL_SHORT, false, 12, off);
|
||||
@ -167,7 +182,7 @@ public abstract class TextureLayer extends RenderElement {
|
||||
GL.glVertexAttribPointer(hTextureTexCoord, 2,
|
||||
GL20.GL_SHORT, false, 12, off + 8);
|
||||
|
||||
int numVertices = ti.vertices - i;
|
||||
int numVertices = t.vertices - i;
|
||||
if (numVertices > maxVertices)
|
||||
numVertices = maxVertices;
|
||||
|
||||
@ -178,7 +193,7 @@ public abstract class TextureLayer extends RenderElement {
|
||||
|
||||
MapRenderer.bindQuadIndicesVBO(false);
|
||||
|
||||
return renderElement.next;
|
||||
return l.next;
|
||||
}
|
||||
|
||||
private final static double COORD_DIV = 1.0 / MapRenderer.COORD_SCALE;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user