packagecom.example.android.image3D;
importandroid.view.SurfaceView;
importandroid.view.SurfaceHolder;
importandroid.content.Context;
importandroid.util.AttributeSet;
importjava.util.ArrayList;
importjava.util.concurrent.Semaphore;
importjavax.microedition.khronos.egl.EGL10;
importjavax.microedition.khronos.egl.EGL11;
importjavax.microedition.khronos.egl.EGLConfig;
importjavax.microedition.khronos.egl.EGLContext;
importjavax.microedition.khronos.egl.EGLDisplay;
importjavax.microedition.khronos.egl.EGLSurface;
importjavax.microedition.khronos.opengles.GL;
importjavax.microedition.khronos.opengles.GL10;
publicclassView3DextendsSurfaceViewimplementsSurfaceHolder.Callback{
privatestaticfinalSemaphoresEglSemaphore=newSemaphore(1);
privatebooleanmSizeChanged=true;
privateSurfaceHoldermHolder;
privateGLThreadmGLThread;
privateGLWrappermGLWrapper;
publicView3D(Contextcontext){
super(context);
init();
}
publicView3D(Contextcontext,AttributeSetattrs){
super(context,attrs);
init();
}
privatevoidinit(){
mHolder=getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
}
publicSurfaceHoldergetSurfaceHolder(){
returnmHolder;
}
publicvoidsetGLWrapper(GLWrapperglWrapper){
mGLWrapper=glWrapper;
}
publicvoidsetRenderer(Rendererrenderer){
mGLThread=newGLThread(renderer);
mGLThread.start();
}
publicvoidsurfaceCreated(SurfaceHolderholder){
mGLThread.surfaceCreated();
}
publicvoidsurfaceDestroyed(SurfaceHolderholder){
mGLThread.surfaceDestroyed();
}
publicvoidsurfaceChanged(SurfaceHolderholder,
intformat,intw,inth){
mGLThread.onWindowResize(w,h);
}
publicvoidonPause(){
mGLThread.onPause();
}
publicvoidonResume(){
mGLThread.onResume();
}
@Override
publicvoidonWindowFocusChanged(booleanhasFocus){
super.onWindowFocusChanged(hasFocus);
mGLThread.onWindowFocusChanged(hasFocus);
}
publicvoidqueueEvent(Runnabler){
mGLThread.queueEvent(r);
}
@Override
protectedvoidonDetachedFromWindow(){
super.onDetachedFromWindow();
mGLThread.requestExitAndWait();
}
publicinterfaceGLWrapper{
GLwrap(GLgl);
}
publicinterfaceRenderer{
int[]getConfigSpec();
voidsurfaceCreated(GL10gl);
voidsizeChanged(GL10gl,intwidth,intheight);
voiddrawFrame(GL10gl);
}
privateclassEglHelper{
EGL10mEgl;
EGLDisplaymEglDisplay;
EGLSurfacemEglSurface;
EGLConfigmEglConfig;
EGLContextmEglContext;
publicEglHelper(){
}
publicvoidstart(int[]configSpec){
mEgl=(EGL10)EGLContext.getEGL();
mEglDisplay=mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
int[]version=newint[2];
mEgl.eglInitialize(mEglDisplay,version);
EGLConfig[]configs=newEGLConfig[1];
int[]num_config=newint[1];
mEgl.eglChooseConfig(mEglDisplay,configSpec,configs,1,
num_config);
mEglConfig=configs[0];
mEglContext=mEgl.eglCreateContext(mEglDisplay,mEglConfig,
EGL10.EGL_NO_CONTEXT,null);
mEglSurface=null;
}
publicGLcreateSurface(SurfaceHolderholder){
if(mEglSurface!=null){
mEgl.eglMakeCurrent(mEglDisplay,EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE,EGL10.EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay,mEglSurface);
}
mEglSurface=mEgl.eglCreateWindowSurface(mEglDisplay,
mEglConfig,holder,null);
mEgl.eglMakeCurrent(mEglDisplay,mEglSurface,mEglSurface,
mEglContext);
GLgl=mEglContext.getGL();
if(mGLWrapper!=null){
gl=mGLWrapper.wrap(gl);
}
returngl;
}
publicbooleanswap(){
mEgl.eglSwapBuffers(mEglDisplay,mEglSurface);
returnmEgl.eglGetError()!=EGL11.EGL_CONTEXT_LOST;
}
publicvoidfinish(){
if(mEglSurface!=null){
mEgl.eglMakeCurrent(mEglDisplay,EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay,mEglSurface);
mEglSurface=null;
}
if(mEglContext!=null){
mEgl.eglDestroyContext(mEglDisplay,mEglContext);
mEglContext=null;
}
if(mEglDisplay!=null){
mEgl.eglTerminate(mEglDisplay);
mEglDisplay=null;
}
}
}
classGLThreadextendsThread{
privatebooleanmDone;
privatebooleanmPaused;
privatebooleanmHasFocus;
privatebooleanmHasSurface;
privatebooleanmContextLost;
privateintmWidth;
privateintmHeight;
privateRenderermRenderer;
privateArrayList
mEventQueue=newArrayList
privateEglHelpermEglHelper;
GLThread(Rendererrenderer){
super();
mDone=false;
mWidth=0;
mHeight=0;
mRenderer=renderer;
setName("GLThread");
}
@Override
publicvoidrun(){
try{
try{
sEglSemaphore.acquire();
}catch(InterruptedExceptione){
return;
}
guardedRun();
}catch(InterruptedExceptione){
}finally{
sEglSemaphore.release();
}
}
privatevoidguardedRun()throwsInterruptedException{
mEglHelper=newEglHelper();
int[]configSpec=mRenderer.getConfigSpec();
mEglHelper.start(configSpec);
GL10gl=null;
booleantellRendererSurfaceCreated=true;
booleantellRendererSurfaceChanged=true;
while(!mDone){
intw,h;
booleanchanged;
booleanneedStart=false;
synchronized(this){
Runnabler;
while((r=getEvent())!=null){
r.run();
}
if(mPaused){
mEglHelper.finish();
needStart=true;
}
if(needToWait()){
while(needToWait()){
wait();
}
}
if(mDone){
break;
}
changed=mSizeChanged;
w=mWidth;
h=mHeight;
mSizeChanged=false;
}
if(needStart){
mEglHelper.start(configSpec);
tellRendererSurfaceCreated=true;
changed=true;
}
if(changed){
gl=(GL10)mEglHelper.createSurface(mHolder);
tellRendererSurfaceChanged=true;
}
if(tellRendererSurfaceCreated){
mRenderer.surfaceCreated(gl);
tellRendererSurfaceCreated=false;
}
if(tellRendererSurfaceChanged){
mRenderer.sizeChanged(gl,w,h);
tellRendererSurfaceChanged=false;
}
if((w>0)&&(h>0)){
mRenderer.drawFrame(gl);
mEglHelper.swap();
}
}
mEglHelper.finish();
}
privatebooleanneedToWait(){
return(mPaused||(!mHasFocus)||(!mHasSurface)||mContextLost)
&&(!mDone);
}
publicvoidsurfaceCreated(){
synchronized(this){
mHasSurface=true;
mContextLost=false;
notify();
}
}
publicvoidsurfaceDestroyed(){
synchronized(this){
mHasSurface=false;
notify();
}
}
publicvoidonPause(){
synchronized(this){
mPaused=true;
}
}
publicvoidonResume(){
synchronized(this){
mPaused=false;
notify();
}
}
publicvoidonWindowFocusChanged(booleanhasFocus){
synchronized(this){
mHasFocus=hasFocus;
if(mHasFocus==true){
notify();
}
}
}
publicvoidonWindowResize(intw,inth){
synchronized(this){
mWidth=w;
mHeight=h;
mSizeChanged=true;
}
}
publicvoidrequestExitAndWait(){
synchronized(this){
mDone=true;
notify();
}
try{
join();
}catch(InterruptedExceptionex){
Thread.currentThread().interrupt();
}
}
publicvoidqueueEvent(Runnabler){
synchronized(this){
mEventQueue.add(r);
}
}
privateRunnablegetEvent(){
synchronized(this){
if(mEventQueue.size()>0){
returnmEventQueue.remove(0);
}
}
returnnull;
}
}
}