An OpenGL ES renderer based on the GLSurfaceView rendering framework.

   
/*
  * Copyright (C) 2008 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */

import  java.io.IOException;
import  java.io.InputStream;
import  java.util.concurrent.Semaphore;

import  javax.microedition.khronos.egl.EGL10;
import  javax.microedition.khronos.egl.EGL11;
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.GL;
import  javax.microedition.khronos.opengles.GL10;
import  javax.microedition.khronos.opengles.GL11;
import  javax.microedition.khronos.opengles.GL11Ext;

import  android.content.Context;
import  android.graphics.Bitmap;
import  android.graphics.BitmapFactory;
import  android.opengl.GLUtils;
import  android.util.AttributeSet;
import  android.util.Log;
import  android.view.SurfaceHolder;
import  android.view.SurfaceView;

/**
  * An OpenGL ES renderer based on the GLSurfaceView rendering framework. This
  * class is responsible for drawing a list of renderables to the screen every
  * frame. It also manages loading of textures and (when VBOs are used) the
  * allocation of vertex buffer objects.
  */
public class  SimpleGLRenderer  implements  GLSurfaceView.Renderer  {
   // Specifies the format our textures should be converted to upon load.
   private static  BitmapFactory.Options sBitmapOptions =  new  BitmapFactory.Options () ;
   // An array of things to draw every frame.
   private  GLSprite []  mSprites;
   // Pre-allocated arrays to use at runtime so that allocation during the
   // test can be avoided.
   private  int []  mTextureNameWorkspace;
   private  int []  mCropWorkspace;
   // A reference to the application context.
   private  Context mContext;

   // Determines the use of vertex arrays.

   // Determines the use of vertex buffer objects.

   public  SimpleGLRenderer ( Context context ) {
     // Pre-allocate and store these objects so we can use them at runtime
     // without allocating memory mid-frame.
     mTextureNameWorkspace =  new  int [ 1 ] ;
     mCropWorkspace =  new  int [ 4 ] ;

     // Set our bitmaps to 16-bit, 565 format.
     sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;

     mContext = context;
   }

   public  int []  getConfigSpec () {
     // We don't need a depth buffer, and don't care about our
     // color depth.
     int []  configSpec =  EGL10.EGL_DEPTH_SIZE,  0 , EGL10.EGL_NONE  } ;
     return  configSpec;
   }

   public  void  setSprites ( GLSprite []  sprites ) {
     mSprites = sprites;
   }

   /**
    * Changes the vertex mode used for drawing.
   
    @param  useVerts
    *            Specifies whether to use a vertex array. If false, the
    *            DrawTexture extension is used.
    @param  useHardwareBuffers
    *            Specifies whether to store vertex arrays in main memory or on
    *            the graphics card. Ignored if useVerts is false.
    */

   /** Draws the sprites. */
   public  void  drawFrame ( GL10 gl ) {
     if  ( mSprites !=  null ) {

       gl.glMatrixMode ( GL10.GL_MODELVIEW ) ;

       for  ( int  x =  0 ; x < mSprites.length; x++ ) {
         mSprites [ x ] .draw ( gl ) ;
       }

     }
   }

   /* Called when the size of the window changes. */
   public  void  sizeChanged ( GL10 gl,  int  width,  int  height ) {
     gl.glViewport ( 0 0 , width, height ) ;

     /*
      * Set our projection matrix. This doesn't have to be done each time we
      * draw, but usually a new projection needs to be set when the viewport
      * is resized.
      */
     gl.glMatrixMode ( GL10.GL_PROJECTION ) ;
     gl.glLoadIdentity () ;
     gl.glOrthof ( 0.0f , width,  0.0f , height,  0.0f 1.0f ) ;

     gl.glShadeModel ( GL10.GL_FLAT ) ;
     gl.glEnable ( GL10.GL_BLEND ) ;
     gl.glBlendFunc ( GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA ) ;
     gl.glColor4x ( 0x10000 0x10000 0x10000 0x10000 ) ;
     gl.glEnable ( GL10.GL_TEXTURE_2D ) ;
   }

   /**
    * Called whenever the surface is created. This happens at startup, and may
    * be called again at runtime if the device context is lost (the screen goes
    * to sleep, etc). This function must fill the contents of vram with texture
    * data and (when using VBOs) hardware vertex arrays.
    */
   public  void  surfaceCreated ( GL10 gl ) {
     /*
      * Some one-time OpenGL initialization can be made here probably based
      * on features of this particular context
      */
     gl.glHint ( GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST ) ;

     gl.glClearColor ( 0.5f 0.5f 0.5f 1 ) ;
     gl.glShadeModel ( GL10.GL_FLAT ) ;
     gl.glDisable ( GL10.GL_DEPTH_TEST ) ;
     gl.glEnable ( GL10.GL_TEXTURE_2D ) ;
     /*
      * By default, OpenGL enables features that improve quality but reduce
      * performance. One might want to tweak that especially on software
      * renderer.
      */
     gl.glDisable ( GL10.GL_DITHER ) ;
     gl.glDisable ( GL10.GL_LIGHTING ) ;

     gl.glClear ( GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT ) ;

     if  ( mSprites !=  null ) {

       // If we are using hardware buffers and the screen lost context
       // then the buffer indexes that we recorded previously are now
       // invalid. Forget them here and recreate them below.

       // Load our texture and set its texture name on all sprites.

       // To keep this sample simple we will assume that sprites that share
       // the same texture are grouped together in our sprite list. A real
       // app would probably have another level of texture management,
       // like a texture hash.

       int  lastLoadedResource = - 1 ;
       int  lastTextureId = - 1 ;

       for  ( int  x =  0 ; x < mSprites.length; x++ ) {
         int  resource = mSprites [ x ] .getResourceId () ;
         if  ( resource != lastLoadedResource ) {
           lastTextureId = loadBitmap ( mContext, gl, resource ) ;
           lastLoadedResource = resource;
         }
         mSprites [ x ] .setTextureName ( lastTextureId ) ;
         // mSprites[x].getGrid().generateHardwareBuffers(gl);

       }
     }
   }

   /**
    * Called when the rendering thread shuts down. This is a good place to
    * release OpenGL ES resources.
   
    @param  gl
    */
   public  void  shutdown ( GL10 gl ) {
     if  ( mSprites !=  null ) {

       int  lastFreedResource = - 1 ;
       int []  textureToDelete =  new  int [ 1 ] ;

       for  ( int  x =  0 ; x < mSprites.length; x++ ) {
         int  resource = mSprites [ x ] .getResourceId () ;
         if  ( resource != lastFreedResource ) {
           textureToDelete [ 0 = mSprites [ x ] .getTextureName () ;
           gl.glDeleteTextures ( 1 , textureToDelete,  0 ) ;
           mSprites [ x ] .setTextureName ( 0 ) ;
         }
       }
     }
   }

   /**
    * Loads a bitmap into OpenGL and sets up the common parameters for 2D
    * texture maps.
    */
   protected  int  loadBitmap ( Context context, GL10 gl,  int  resourceId ) {
     int  textureName = - 1 ;
     if  ( context !=  null  && gl !=  null ) {
       gl.glGenTextures ( 1 , mTextureNameWorkspace,  0 ) ;

       textureName = mTextureNameWorkspace [ 0 ] ;
       gl.glBindTexture ( GL10.GL_TEXTURE_2D, textureName ) ;

       gl.glTexParameterf ( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
           GL10.GL_NEAREST ) ;
       gl.glTexParameterf ( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
           GL10.GL_LINEAR ) ;

       gl.glTexParameterf ( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
           GL10.GL_CLAMP_TO_EDGE ) ;
       gl.glTexParameterf ( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
           GL10.GL_CLAMP_TO_EDGE ) ;

       gl.glTexEnvf ( GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
           GL10.GL_REPLACE ) ;

       InputStream is = context.getResources () .openRawResource ( resourceId ) ;
       Bitmap bitmap;
       try  {
         bitmap = BitmapFactory.decodeStream ( is, null, sBitmapOptions ) ;
       finally  {
         try  {
           is.close () ;
         catch  ( IOException e ) {
           // Ignore.
         }
       }

       GLUtils.texImage2D ( GL10.GL_TEXTURE_2D,  0 , bitmap,  0 ) ;

       mCropWorkspace [ 0 0 ;
       mCropWorkspace [ 1 = bitmap.getHeight () ;
       mCropWorkspace [ 2 = bitmap.getWidth () ;
       mCropWorkspace [ 3 = -bitmap.getHeight () ;

       bitmap.recycle () ;

       (( GL11 gl ) .glTexParameteriv ( GL10.GL_TEXTURE_2D,
           GL11Ext.GL_TEXTURE_CROP_RECT_OES, mCropWorkspace,  0 ) ;

       int  error = gl.glGetError () ;
       if  ( error != GL10.GL_NO_ERROR ) {
         Log.e ( "SpriteMethodTest" "Texture Load GLError: "  + error ) ;
       }

     }

     return  textureName;
   }

}

/**
  * Base class defining the core set of information necessary to render (and move
  * an object on the screen. This is an abstract type and must be derived to add
  * methods to actually draw (see CanvasSprite and GLSprite).
  */
abstract class  Renderable  {
   // Position.
   public  float  x;
   public  float  y;
   public  float  z;

   // Velocity.
   public  float  velocityX;
   public  float  velocityY;
   public  float  velocityZ;

   // Size.
   public  float  width;
   public  float  height;
}

/**
  * This is the OpenGL ES version of a sprite. It is more complicated than the
  * CanvasSprite class because it can be used in more than one way. This class
  * can draw using a grid of verts, a grid of verts stored in VBO objects, or
  * using the DrawTexture extension.
  */
class  GLSprite  extends  Renderable  {
   // The OpenGL ES texture handle to draw.
   private  int  mTextureName;
   // The id of the original resource that mTextureName is based on.
   private  int  mResourceId;

   // If drawing with verts or VBO verts, the grid object defining those verts.

   public  GLSprite ( int  resourceId ) {
     super () ;
     mResourceId = resourceId;
   }

   public  void  setTextureName ( int  name ) {
     mTextureName = name;
   }

   public  int  getTextureName () {
     return  mTextureName;
   }

   public  void  setResourceId ( int  id ) {
     mResourceId = id;
   }

   public  int  getResourceId () {
     return  mResourceId;
   }

   public  void  draw ( GL10 gl ) {
     gl.glBindTexture ( GL10.GL_TEXTURE_2D, mTextureName ) ;

     // Draw using the DrawTexture extension.
     (( GL11Ext gl ) .glDrawTexfOES ( x, y, z, width, height ) ;

   }
}

/**
  * An implementation of SurfaceView that uses the dedicated surface for
  * displaying an OpenGL animation. This allows the animation to run in a
  * separate thread, without requiring that it be driven by the update mechanism
  * of the view hierarchy.
 
  * The application-specific rendering code is delegated to a GLView.Renderer
  * instance.
  */
class  GLSurfaceView  extends  SurfaceView  implements  SurfaceHolder.Callback  {
   public  GLSurfaceView ( Context context ) {
     super ( context ) ;
     init () ;
   }

   public  GLSurfaceView ( Context context, AttributeSet attrs ) {
     super ( context, attrs ) ;
     init () ;
   }

   private  void  init () {
     // Install a SurfaceHolder.Callback so we get notified when the
     // underlying surface is created and destroyed
     mHolder = getHolder () ;
     mHolder.addCallback ( this ) ;
     mHolder.setType ( SurfaceHolder.SURFACE_TYPE_GPU ) ;
   }

   public  SurfaceHolder getSurfaceHolder () {
     return  mHolder;
   }

   public  void  setGLWrapper ( GLWrapper glWrapper ) {
     mGLWrapper = glWrapper;
   }

   public  void  setRenderer ( Renderer renderer ) {
     mGLThread =  new  GLThread ( renderer ) ;
     mGLThread.start () ;
   }

   public  void  surfaceCreated ( SurfaceHolder holder ) {
     mGLThread.surfaceCreated () ;
   }

   public  void  surfaceDestroyed ( SurfaceHolder holder ) {
     // Surface will be destroyed when we return
     mGLThread.surfaceDestroyed () ;
   }

   public  void  surfaceChanged ( SurfaceHolder holder,  int  format,  int  w,  int  h ) {
     // Surface size or format has changed. This should not happen in this
     // example.
     mGLThread.onWindowResize ( w, h ) ;
   }

   /**
    * Inform the view that the activity is paused.
    */
   public  void  onPause () {
     mGLThread.onPause () ;
   }

   /**
    * Inform the view that the activity is resumed.
    */
   public  void  onResume () {
     mGLThread.onResume () ;
   }

   /**
    * Inform the view that the window focus has changed.
    */
   @Override
   public  void  onWindowFocusChanged ( boolean  hasFocus ) {
     super .onWindowFocusChanged ( hasFocus ) ;
     mGLThread.onWindowFocusChanged ( hasFocus ) ;
   }

   /**
    * Set an "event" to be run on the GL rendering thread.
   
    @param  r
    *            the runnable to be run on the GL rendering thread.
    */
   public  void  setEvent ( Runnable r ) {
     mGLThread.setEvent ( r ) ;
   }

   @Override
   protected  void  onDetachedFromWindow () {
     super .onDetachedFromWindow () ;
     mGLThread.requestExitAndWait () ;
   }

   // ----------------------------------------------------------------------

   public interface  GLWrapper  {
     GL wrap ( GL gl ) ;
   }

   // ----------------------------------------------------------------------

   /**
    * A generic renderer interface.
    */
   public interface  Renderer  {
     /**
      @return  the EGL configuration specification desired by the renderer.
      */
     int []  getConfigSpec () ;

     /**
      * Surface created. Called when the surface is created. Called when the
      * application starts, and whenever the GPU is reinitialized. This will
      * typically happen when the device awakes after going to sleep. Set
      * your textures here.
      */
     void  surfaceCreated ( GL10 gl ) ;

     /**
      * Called when the rendering thread is about to shut down. This is a
      * good place to release OpenGL ES resources (textures, buffers, etc).
     
      @param  gl
      */
     void  shutdown ( GL10 gl ) ;

     /**
      * Surface changed size. Called after the surface is created and
      * whenever the OpenGL ES surface size changes. Set your viewport here.
     
      @param  gl
      @param  width
      @param  height
      */
     void  sizeChanged ( GL10 gl,  int  width,  int  height ) ;

     /**
      * Draw the current frame.
     
      @param  gl
      */
     void  drawFrame ( GL10 gl ) ;
   }

   /**
    * An EGL helper class.
    */

   private class  EglHelper  {
     public  EglHelper () {

     }

     /**
      * Initialize EGL for a given configuration spec.
     
      @param  configSpec
      */
     public  void  start ( int []  configSpec ) {
       /*
        * Get an EGL instance
        */
       mEgl =  ( EGL10 EGLContext.getEGL () ;

       /*
        * Get to the default display.
        */
       mEglDisplay = mEgl.eglGetDisplay ( EGL10.EGL_DEFAULT_DISPLAY ) ;

       /*
        * We can now initialize EGL for that display
        */
       int []  version =  new  int [ 2 ] ;
       mEgl.eglInitialize ( mEglDisplay, version ) ;

       EGLConfig []  configs =  new  EGLConfig [ 1 ] ;
       int []  num_config =  new  int [ 1 ] ;
       mEgl.eglChooseConfig ( mEglDisplay, configSpec, configs,  1 ,
           num_config ) ;
       mEglConfig = configs [ 0 ] ;

       /*
        * Create an OpenGL ES context. This must be done only once, an
        * OpenGL context is a somewhat heavy object.
        */
       mEglContext = mEgl.eglCreateContext ( mEglDisplay, mEglConfig,
           EGL10.EGL_NO_CONTEXT,  null ) ;

       mEglSurface =  null ;
     }

     /*
      * Create and return an OpenGL surface
      */
     public  GL createSurface ( SurfaceHolder holder ) {
       /*
        * The window size has changed, so we need to create a new surface.
        */
       if  ( mEglSurface !=  null ) {

         /*
          * Unbind and destroy the old EGL surface, if there is one.
          */
         mEgl.eglMakeCurrent ( mEglDisplay, EGL10.EGL_NO_SURFACE,
             EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT ) ;
         mEgl.eglDestroySurface ( mEglDisplay, mEglSurface ) ;
       }

       /*
        * Create an EGL surface we can render into.
        */
       mEglSurface = mEgl.eglCreateWindowSurface ( mEglDisplay, mEglConfig,
           holder,  null ) ;

       /*
        * Before we can issue GL commands, we need to make sure the context
        * is current and bound to a surface.
        */
       mEgl.eglMakeCurrent ( mEglDisplay, mEglSurface, mEglSurface,
           mEglContext ) ;

       GL gl = mEglContext.getGL () ;
       if  ( mGLWrapper !=  null ) {
         gl = mGLWrapper.wrap ( gl ) ;
       }
       return  gl;
     }

     /**
      * Display the current render surface.
     
      @return  false if the context has been lost.
      */
     public  boolean  swap () {
       mEgl.eglSwapBuffers ( mEglDisplay, mEglSurface ) ;

       /*
        * Always check for EGL_CONTEXT_LOST, which means the context and
        * all associated data were lost (For instance because the device
        * went to sleep). We need to sleep until we get a new surface.
        */
       return  mEgl.eglGetError ()  != EGL11.EGL_CONTEXT_LOST;
     }

     public  void  finish () {
       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 ;
       }
     }

     EGL10 mEgl;
     EGLDisplay mEglDisplay;
     EGLSurface mEglSurface;
     EGLConfig mEglConfig;
     EGLContext mEglContext;
   }

   /**
    * A generic GL Thread. Takes care of initializing EGL and GL. Delegates to
    * a Renderer instance to do the actual drawing.
   
    */

   class  GLThread  extends  Thread  {
     GLThread ( Renderer renderer ) {
       super () ;
       mDone =  false ;
       mWidth =  0 ;
       mHeight =  0 ;
       mRenderer = renderer;
       setName ( "GLThread" ) ;
     }

     @Override
     public  void  run () {
       /*
        * When the android framework launches a second instance of an
        * activity, the new instance's onCreate() method may be called
        * before the first instance returns from onDestroy().
       
        * This semaphore ensures that only one instance at a time accesses
        * EGL.
        */
       try  {
         try  {
           sEglSemaphore.acquire () ;
         catch  ( InterruptedException e ) {
           return ;
         }
         guardedRun () ;
       catch  ( InterruptedException e ) {
         // fall thru and exit normally
       finally  {
         sEglSemaphore.release () ;
       }
     }

     private  void  guardedRun ()  throws  InterruptedException  {
       mEglHelper =  new  EglHelper () ;
       /*
        * Specify a configuration for our opengl session and grab the first
        * configuration that matches is
        */
       int []  configSpec = mRenderer.getConfigSpec () ;
       mEglHelper.start ( configSpec ) ;

       GL10 gl =  null ;
       boolean  tellRendererSurfaceCreated =  true ;
       boolean  tellRendererSurfaceChanged =  true ;

       /*
        * This is our main activity thread's loop, we go until asked to
        * quit.
        */
       while  ( !mDone ) {

         /*
          * Update the asynchronous state (window size)
          */
         int  w, h;
         boolean  changed;
         boolean  needStart =  false ;
         synchronized  ( this ) {
           if  ( mEvent !=  null ) {

             mEvent.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 )) {

           /* draw a frame here */
           mRenderer.drawFrame ( gl ) ;

           /*
            * Once we're done with GL, we need to call swapBuffers() to
            * instruct the system to display the rendered frame
            */

           mEglHelper.swap () ;

         }

       }

       /*
        * clean-up everything...
        */
       if  ( gl !=  null ) {
         mRenderer.shutdown ( gl ) ;
       }

       mEglHelper.finish () ;
     }

     private  boolean  needToWait () {
       return  ( mPaused ||  ( !mHasFocus ||  ( !mHasSurface || mContextLost )
           &&  ( !mDone ) ;
     }

     public  void  surfaceCreated () {
       synchronized  ( this ) {
         mHasSurface =  true ;
         mContextLost =  false ;
         notify () ;
       }
     }

     public  void  surfaceDestroyed () {
       synchronized  ( this ) {
         mHasSurface =  false ;
         notify () ;
       }
     }

     public  void  onPause () {
       synchronized  ( this ) {
         mPaused =  true ;
       }
     }

     public  void  onResume () {
       synchronized  ( this ) {
         mPaused =  false ;
         notify () ;
       }
     }

     public  void  onWindowFocusChanged ( boolean  hasFocus ) {
       synchronized  ( this ) {
         mHasFocus = hasFocus;
         if  ( mHasFocus ==  true ) {
           notify () ;
         }
       }
     }

     public  void  onWindowResize ( int  w,  int  h ) {
       synchronized  ( this ) {
         mWidth = w;
         mHeight = h;
         mSizeChanged =  true ;
       }
     }

     public  void  requestExitAndWait () {
       // don't call this from GLThread thread or it is a guaranteed
       // deadlock!
       synchronized  ( this ) {
         mDone =  true ;
         notify () ;
       }
       try  {
         join () ;
       catch  ( InterruptedException ex ) {
         Thread.currentThread () .interrupt () ;
       }
     }

     /**
      * Queue an "event" to be run on the GL rendering thread.
     
      @param  r
      *            the runnable to be run on the GL rendering thread.
      */
     public  void  setEvent ( Runnable r ) {
       synchronized  ( this ) {
         mEvent = r;
       }
     }

     public  void  clearEvent () {
       synchronized  ( this ) {
         mEvent =  null ;
       }
     }

     private  boolean  mDone;
     private  boolean  mPaused;
     private  boolean  mHasFocus;
     private  boolean  mHasSurface;
     private  boolean  mContextLost;
     private  int  mWidth;
     private  int  mHeight;
     private  Renderer mRenderer;
     private  Runnable mEvent;
     private  EglHelper mEglHelper;
   }

   private static final  Semaphore sEglSemaphore =  new  Semaphore ( 1 ) ;
   private  boolean  mSizeChanged =  true ;

   private  SurfaceHolder mHolder;
   private  GLThread mGLThread;
   private  GLWrapper mGLWrapper;
}

   

你可能感兴趣的:(JOIN,filter,null,buffer,Blend,textures)