org.oscim.renderer.bucket.TextureItem Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vtm Show documentation
Show all versions of vtm Show documentation
OpenGL vector map library written in Java - running on Android, iOS, Desktop and within the browser.
/*
* Copyright 2012, 2013 Hannes Janetzek
* Copyright 2016 devemux86
* Copyright 2017 Longri
*
* 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 .
*/
package org.oscim.renderer.bucket;
import org.oscim.backend.CanvasAdapter;
import org.oscim.backend.GL;
import org.oscim.backend.canvas.Bitmap;
import org.oscim.backend.canvas.Color;
import org.oscim.renderer.GLState;
import org.oscim.renderer.GLUtils;
import org.oscim.utils.pool.Inlist;
import org.oscim.utils.pool.SyncPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import javax.annotation.CheckReturnValue;
import static org.oscim.backend.GLAdapter.gl;
public class TextureItem extends Inlist {
static final Logger log = LoggerFactory.getLogger(TextureItem.class);
static final boolean dbg = false;
/**
* texture ID
*/
int id;
/**
* current settings
*/
public final int width;
public final int height;
public final boolean repeat;
/**
* vertex offset from which this texture is referenced
*/
/* FIXME dont put this here! */
public int offset;
public int indices;
/**
* temporary Bitmap
*/
public Bitmap bitmap;
/**
* do not release the texture when TextureItem is released.
*/
private TextureItem ref;
private int used = 0;
/**
* texture data is ready
*/
boolean loaded;
final TexturePool pool;
public boolean mipmap;
private TextureItem(TexturePool pool, int id) {
this(pool, id, pool.mWidth, pool.mHeight, false);
}
public TextureItem(Bitmap bitmap) {
this(bitmap, false);
}
public TextureItem(Bitmap bitmap, boolean repeat) {
this(NOPOOL, -1, bitmap.getWidth(), bitmap.getHeight(), repeat);
this.bitmap = bitmap;
}
private TextureItem(TexturePool pool, int id, int width, int height, boolean repeat) {
this.id = id;
this.width = width;
this.height = height;
this.pool = pool;
this.repeat = repeat;
}
public static TextureItem clone(TextureItem ti) {
TextureItem clone = new TextureItem(NOPOOL, ti.id, ti.width, ti.height, ti.repeat);
clone.id = ti.id;
clone.ref = (ti.ref == null) ? ti : ti.ref;
clone.loaded = ti.loaded;
clone.ref.used++;
return clone;
}
/**
* Upload Image to Texture
* [on GL-Thread]
*/
public void upload() {
if (loaded)
return;
if (ref == null) {
pool.uploadTexture(this);
} else {
/* load referenced texture */
ref.upload();
id = ref.id;
}
loaded = true;
}
/**
* Bind Texture for rendering
* [on GL-Thread]
*/
public void bind() {
if (loaded)
GLState.bindTex2D(id);
else
upload();
}
/**
* Dispose TextureItem
* [Threadsafe]
*
* @return this.next
*/
@CheckReturnValue
public TextureItem dispose() {
TextureItem n = this.next;
this.next = null;
pool.release(this);
return n;
}
public static class TexturePool extends SyncPool {
private final ArrayList mBitmaps = new ArrayList(10);
private final int mHeight;
private final int mWidth;
private final boolean mUseBitmapPool;
private final boolean mMipmaps;
//private final int mBitmapFormat;
//private final int mBitmapType;
protected int mTexCnt = 0;
public TexturePool(int maxFill, int width, int height, boolean mipmap) {
super(maxFill);
mWidth = width;
mHeight = height;
mUseBitmapPool = true;
mMipmaps = mipmap;
}
public TexturePool(int maxFill) {
super(maxFill);
mWidth = 0;
mHeight = 0;
mUseBitmapPool = false;
mMipmaps = false;
}
@Override
public TextureItem releaseAll(TextureItem t) {
throw new RuntimeException("use TextureItem.dispose()");
}
/**
* Retrieve a TextureItem from pool.
*/
@Override
public synchronized TextureItem get() {
TextureItem t = super.get();
if (!mUseBitmapPool)
return t;
synchronized (mBitmaps) {
int size = mBitmaps.size();
if (size == 0)
t.bitmap = CanvasAdapter.newBitmap(mWidth, mHeight, 0);
else {
t.bitmap = mBitmaps.remove(size - 1);
t.bitmap.eraseColor(Color.TRANSPARENT);
}
}
return t;
}
public synchronized TextureItem get(Bitmap bitmap) {
TextureItem t = super.get();
t.bitmap = bitmap;
return t;
}
@Override
protected TextureItem createItem() {
return new TextureItem(this, -1);
}
@Override
protected boolean clearItem(TextureItem t) {
if (t.used > 0)
return false;
if (t.ref != null) {
/* dispose texture if this clone holds the last handle */
if (t.ref.used == 0) {
t.ref.dispose();
return false;
}
t.ref.used--;
return false;
}
t.loaded = false;
if (mUseBitmapPool)
releaseBitmap(t);
return t.id >= 0;
}
@Override
protected void freeItem(TextureItem t) {
if (t.ref == null && t.used == 0 && t.id >= 0) {
mTexCnt--;
synchronized (disposedTextures) {
disposedTextures.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");
if (t.id < 0) {
int[] textureIds = GLUtils.glGenTextures(1);
t.id = textureIds[0];
t.mipmap |= mMipmaps;
initTexture(t);
if (dbg)
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.mipmap)
gl.generateMipmap(GL.TEXTURE_2D);
if (dbg)
GLUtils.checkGlError(getClass().getName());
if (mUseBitmapPool)
releaseBitmap(t);
}
protected void initTexture(TextureItem t) {
GLState.bindTex2D(t.id);
if (t.mipmap) {
gl.texParameterf(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER,
GL.LINEAR_MIPMAP_LINEAR);
} else {
gl.texParameterf(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER,
GL.LINEAR);
}
gl.texParameterf(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER,
GL.LINEAR);
if (t.repeat) {
gl.texParameterf(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S,
GL.REPEAT);
gl.texParameterf(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T,
GL.REPEAT);
} else {
gl.texParameterf(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S,
GL.CLAMP_TO_EDGE);
gl.texParameterf(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T,
GL.CLAMP_TO_EDGE);
}
}
}
/* Pool for not-pooled textures. Disposed items will only be released
* on the GL-Thread and will not be put back in any pool. */
static final TexturePool NOPOOL = new TexturePool(0);
static final ArrayList disposedTextures = new ArrayList();
/**
* Disposed textures are released by MapRenderer after each frame
*/
public static void disposeTextures() {
synchronized (disposedTextures) {
int size = disposedTextures.size();
if (size > 0) {
int[] tmp = new int[size];
for (int i = 0; i < size; i++)
tmp[i] = disposedTextures.get(i).intValue();
disposedTextures.clear();
GLUtils.glDeleteTextures(size, tmp);
}
}
}
}