package com.asha.vrlib.texture; import android.graphics.Bitmap; import android.opengl.GLES20; import android.opengl.GLUtils; import com.asha.vrlib.MD360Program; import com.asha.vrlib.MDVRLibrary; import com.asha.vrlib.common.MDMainHandler; import java.lang.ref.SoftReference; import java.util.concurrent.atomic.AtomicBoolean; import static com.asha.vrlib.common.GLUtil.glCheck; import static com.asha.vrlib.common.VRUtil.notNull; /** * Created by hzqiujiadi on 16/4/5. * hzqiujiadi ashqalcn@gmail.com */ public class MD360BitmapTexture extends MD360Texture { private static final String TAG = "MD360BitmapTexture"; private MDVRLibrary.IBitmapProvider mBitmapProvider; private boolean mIsReady; private AsyncCallback mTmpAsyncCallback; private AtomicBoolean mTextureDirty = new AtomicBoolean(false); public MD360BitmapTexture(MDVRLibrary.IBitmapProvider bitmapProvider) { this.mBitmapProvider = bitmapProvider; } @Override protected int createTextureId() { final int[] textureHandle = new int[1]; GLES20.glGenTextures(1, textureHandle, 0); final int textureId = textureHandle[0]; // call the provider // to load the bitmap. loadTexture(); return textureId; } // gl thread @Override public boolean texture(MD360Program program) { if (mTextureDirty.get()){ loadTexture(); mTextureDirty.set(false); } AsyncCallback asyncCallback = mTmpAsyncCallback; int textureId = getCurrentTextureId(); if (asyncCallback != null && asyncCallback.hasBitmap()){ Bitmap bitmap = asyncCallback.getBitmap(); textureInThread(textureId, program, bitmap); asyncCallback.releaseBitmap(); mIsReady = true; } if (isReady() && textureId != 0){ GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); GLES20.glUniform1i(program.getTextureUniformHandle(), 0); } return true; } @Override public void notifyChanged() { mTextureDirty.set(true); } // call from gl thread private void loadTexture(){ // release the ref before if (mTmpAsyncCallback != null){ mTmpAsyncCallback.releaseBitmap(); mTmpAsyncCallback = null; } // get texture max size. int[] maxSize = new int[1]; GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxSize, 0); // create a new one mTmpAsyncCallback = new AsyncCallback(maxSize[0]); MDMainHandler.sharedHandler().post(new Runnable() { @Override public void run() { mBitmapProvider.onProvideBitmap(mTmpAsyncCallback); } }); } @Override public boolean isReady() { return mIsReady; } @Override public void destroy() { // release the ref before if (mTmpAsyncCallback != null){ mTmpAsyncCallback.releaseBitmap(); mTmpAsyncCallback = null; } } @Override public void release() { } private void textureInThread(int textureId, MD360Program program, Bitmap bitmap) { notNull(bitmap, "bitmap can't be null!"); if (isEmpty(textureId)) return; GLES20.glActiveTexture(GLES20.GL_TEXTURE0); glCheck("MD360BitmapTexture glActiveTexture"); // Bind to the texture in OpenGL GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); glCheck("MD360BitmapTexture glBindTexture"); // Set filtering GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE); // Load the bitmap into the bound texture. GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); glCheck("MD360BitmapTexture texImage2D"); GLES20.glUniform1i(program.getTextureUniformHandle(),0); glCheck("MD360BitmapTexture textureInThread"); } private static class AsyncCallback implements Callback { private SoftReference<Bitmap> bitmapRef; private int maxSize; public AsyncCallback(int maxSize) { this.maxSize = maxSize; } @Override public void texture(Bitmap bitmap) { this.bitmapRef = new SoftReference<>(bitmap); } @Override public int getMaxTextureSize() { return maxSize; } public Bitmap getBitmap(){ return bitmapRef != null ? bitmapRef.get() : null; } public boolean hasBitmap(){ return bitmapRef != null && bitmapRef.get() != null; } public void releaseBitmap(){ if (bitmapRef != null){ bitmapRef.clear(); } bitmapRef = null; } } public interface Callback { void texture(Bitmap bitmap); int getMaxTextureSize(); } }