/*
PixelBuffer.java
Copyright (c) 2015 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.deviceplugin.theta.opengl;
import android.graphics.Bitmap;
import android.opengl.GLSurfaceView;
import org.deviceconnect.android.deviceplugin.theta.BuildConfig;
import java.nio.IntBuffer;
import java.util.logging.Logger;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL10;
import static javax.microedition.khronos.egl.EGL10.EGL_ALPHA_SIZE;
import static javax.microedition.khronos.egl.EGL10.EGL_BLUE_SIZE;
import static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY;
import static javax.microedition.khronos.egl.EGL10.EGL_DEPTH_SIZE;
import static javax.microedition.khronos.egl.EGL10.EGL_GREEN_SIZE;
import static javax.microedition.khronos.egl.EGL10.EGL_HEIGHT;
import static javax.microedition.khronos.egl.EGL10.EGL_NONE;
import static javax.microedition.khronos.egl.EGL10.EGL_NO_CONTEXT;
import static javax.microedition.khronos.egl.EGL10.EGL_RED_SIZE;
import static javax.microedition.khronos.egl.EGL10.EGL_RENDERABLE_TYPE;
import static javax.microedition.khronos.egl.EGL10.EGL_STENCIL_SIZE;
import static javax.microedition.khronos.egl.EGL10.EGL_WIDTH;
import static javax.microedition.khronos.opengles.GL10.GL_RGBA;
import static javax.microedition.khronos.opengles.GL10.GL_UNSIGNED_BYTE;
/**
* Pixel Buffer.
*
* @author NTT DOCOMO, INC.
*/
public class PixelBuffer {
private final Logger mLogger = Logger.getLogger("theta.dplugin");
private final int mWidth;
private final int mHeight;
private final EGL10 mEGL;
private final EGLDisplay mEGLDisplay;
private final EGLConfig[] mEGLConfigs;
private final EGLConfig mEGLConfig;
private final EGLContext mEGLContext;
private final EGLSurface mEGLSurface;
private final GL10 mGL;
private final String mThreadOwner;
private GLSurfaceView.Renderer mRenderer;
private IntBuffer mIb;
private final Bitmap mBitmap;
public PixelBuffer(final int width, final int height, final boolean isStereo) {
mWidth = isStereo ? width * 2 : width;
mHeight = height;
mIb = IntBuffer.allocate(mWidth * mHeight);
mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
mEGL = (EGL10) EGLContext.getEGL();
mEGLDisplay = mEGL.eglGetDisplay(EGL_DEFAULT_DISPLAY);
int[] version = new int[2];
mEGL.eglInitialize(mEGLDisplay, version);
mEGLConfigs = chooseConfigs();
mEGLConfig = mEGLConfigs[0];
mEGLContext = mEGL.eglCreateContext(mEGLDisplay, mEGLConfig, EGL_NO_CONTEXT, new int[] {
0x3098, // EGL_CONTEXT_CLIENT_VERSION
2, // OpenGL ES 2.0
EGL10.EGL_NONE });
mEGLSurface = mEGL.eglCreatePbufferSurface(mEGLDisplay, mEGLConfig, new int[] {
EGL_WIDTH, mWidth,
EGL_HEIGHT, mHeight,
EGL_NONE
});
mEGL.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
mGL = (GL10) mEGLContext.getGL();
mThreadOwner = Thread.currentThread().getName();
}
private void checkEGLError(EGL10 egl) {
int error = egl.eglGetError();
if (BuildConfig.DEBUG) {
if (error == EGL10.EGL_SUCCESS) {
mLogger.info("EGL SUCCESS.");
} else {
mLogger.severe("EGL Error: " + error);
}
}
}
public void destroy() {
mEGL.eglDestroySurface(mEGLDisplay, mEGLSurface);
mEGL.eglDestroyContext(mEGLDisplay, mEGLContext);
mEGL.eglTerminate(mEGLDisplay);
}
public void setRenderer(GLSurfaceView.Renderer renderer) {
mRenderer = renderer;
if (!Thread.currentThread().getName().equals(mThreadOwner)) {
mLogger.severe("setRenderer: This thread does not own the OpenGL context.");
return;
}
mRenderer.onSurfaceCreated(mGL, mEGLConfig);
}
public void render() {
if (mRenderer == null) {
mLogger.severe("PixelBuffer.render: Renderer was not set.");
return;
}
if (!Thread.currentThread().getName().equals(mThreadOwner)) {
mLogger.severe("PixelBuffer.render: This thread does not own the OpenGL context.");
return;
}
mRenderer.onDrawFrame(mGL);
}
private EGLConfig[] chooseConfigs() {
int[] attribList = new int[] {
EGL_DEPTH_SIZE, 0,
EGL_STENCIL_SIZE, 0,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_RENDERABLE_TYPE, 4, // OpenGL ES 2.0
EGL_NONE
};
int[] numConfig = new int[1];
mEGL.eglChooseConfig(mEGLDisplay, attribList, null, 0, numConfig);
int configSize = numConfig[0];
EGLConfig[] eGLConfigs = new EGLConfig[configSize];
mEGL.eglChooseConfig(mEGLDisplay, attribList, eGLConfigs, configSize, numConfig);
return eGLConfigs;
}
public Bitmap convertToBitmap() {
mGL.glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, mIb);
mBitmap.copyPixelsFromBuffer(mIb);
mIb.clear();
return mBitmap;
}
}