Ch10 Listings

satya - Friday, June 12, 2009 10:49:22 PM

Listing 10-1. Example of glDrawElements


glDrawElements(
   // type of shape
   GL10.GL_TRIANGLE_STRIP,
   // Number of indices
   3,
   // How big each index is
   GL10.GL_UNSIGNED_SHORT,
   // buffer containing the 3 indices
   mIndexBuffer);

satya - Friday, June 12, 2009 10:53:32 PM

Listing 10-2. Sample Code to Get an EGL Context


//Ask for an implementation of EGL10
EGL10 mEgl = (EGL10) EGLContext.getEGL();

//get the default display
EGLDisplay mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

//initialize the display
int[] version = new int[2];
mEgl.eglInitialize(mEglDisplay, version);

//config spec
int[] configSpec = {
   EGL10.EGL_DEPTH_SIZE, 0,
   EGL10.EGL_NONE
};

EGLConfig[] configs = new EGLConfig[1];
int[] num_config = new int[1];

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

//Create EGL Context
mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig,
EGL10.EGL_NO_CONTEXT, null);

satya - Friday, June 12, 2009 10:56:21 PM

Listing 10-3. Getting a Reference to the OpenGL ES Interface


android.view.SurfaceHolder holder = surfaceView.getHolder();

// mEgl points to an EGL context interface EGL10
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay,
                                 mEglConfig, holder, null);
                                 
mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
                  mEglContext);
GL gl = mEgl.getGL();

satya - Friday, June 12, 2009 10:57:42 PM

Listing 10-4. Associating and Disassociating the Window Surface


mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
            EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);

satya - Friday, June 12, 2009 10:59:01 PM

Listing 10-5. Closing Out OpenGL ES Resources


//Destroy surface
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                  EGL10.EGL_NO_SURFACE,
                  EGL10.EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);

//Destroy context
mEgl.eglDestroyContext(mEglDisplay, mEglContext);

//Disassociate display
mEgl.eglTerminate(mEglDisplay);

satya - Friday, June 12, 2009 11:02:50 PM

Listing 10-6. Code for the OpenGLTestHarnessActivity Class


// filename: OpenGLTestHarnessActivity.java
public class OpenGLTestHarnessActivity extends Activity 
{
   private OpenGLTestHarness mTestHarness;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      mTestHarness = new OpenGLTestHarness(this);
      mTestHarness.setRenderer(new SimpleTriangleRenderer(this));
      setContentView(mTestHarness);
   }

   @Override
   protected void onResume() {
   super.onResume();
   mTestHarness.onResume();
   }

   @Override
   protected void onPause() {
      super.onPause();
      mTestHarness.onPause();
   }
}

satya - Friday, June 12, 2009 11:06:29 PM

Listing 10-7. The OpenGLTestHarness Class


// filename: OpenGLTestHarness.java
public class OpenGLTestHarness extends SurfaceView
implements SurfaceHolder.Callback
{
   public static final Semaphore sEglSemaphore = new Semaphore(1);
   public boolean mSizeChanged = true;
   public SurfaceHolder mHolder;
   private OpenGLDrawingThread mGLThread;

   public OpenGLTestHarness(Context context) {
      super(context);
      init();
   }

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

   private void init() {
      mHolder = getHolder();
      mHolder.addCallback(this);
      mHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
   }

   public SurfaceHolder getSurfaceHolder() {
      return mHolder;
   }

   public void setRenderer(Renderer renderer) {
      mGLThread = new OpenGLDrawingThread(this,renderer);
      mGLThread.start();
   }

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

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

   public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
      mGLThread.onWindowResize(w, h);
   }

   public void onPause() {
      mGLThread.onPause();
   }

   public void onResume() {
      mGLThread.onResume();
   }

   @Override public void onWindowFocusChanged(boolean hasFocus) {
      super.onWindowFocusChanged(hasFocus);
      mGLThread.onWindowFocusChanged(hasFocus);
   }

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

satya - Friday, June 12, 2009 11:21:34 PM

Listing 10-8. The OpenGLDrawingThread Class


// filename: OpenGLDrawingThread.java
class OpenGLDrawingThread extends Thread
{
   private boolean mDone, mPaused, mHasFocus;
   private boolean mHasSurface, mContextLost, mSizeChanged;
   private int mWidth,mHeight;

   private Renderer mRenderer;
   private EglHelper mEglHelper;
   private OpenGLTestHarness pSv = null;

   OpenGLDrawingThread(OpenGLTestHarness sv, Renderer renderer) {
      super();
      mDone = false; mWidth = 0; mHeight = 0;
      mRenderer = renderer; mSizeChanged = false;
      setName("GLThread");
      pSv = sv;
   }

   @Override
   public void run() {
      try {
         try {
            OpenGLTestHarness.sEglSemaphore.acquire();
         } catch (InterruptedException e) {
            return;
         }
         guardedRun();
      } catch (InterruptedException e) {
         // fall thru and exit normally
      } finally {
         OpenGLTestHarness.sEglSemaphore.release();
      }
   }

   private void guardedRun() throws InterruptedException {
      mEglHelper = new EglHelper();
      int[] configSpec = mRenderer.getConfigSpec();
      mEglHelper.start(configSpec);
      GL10 gl = null;
      boolean tellRendererSurfaceCreated = true;
      boolean tellRendererSurfaceChanged = true;

      while (!mDone)
      {
         int w, h;
         boolean changed;
         boolean needStart = false;

         synchronized (this) {
            if (mPaused) {
               Log.d("x", "Paused");
               mEglHelper.finish();
               needStart = true;
            }
            if(needToWait()) {
               while (needToWait()) {
                  wait();
                  Log.d("x", "woke up from wait");
               }
            }
            if (mDone) {
               break;
            }
            changed = pSv.mSizeChanged;
            w = mWidth;
            h = mHeight;
            pSv.mSizeChanged = false;
            this.mSizeChanged = false;
         }
         if (needStart) {
            Log.d("x", "Need to start");
            mEglHelper.start(configSpec);
            tellRendererSurfaceCreated = true;
            changed = true;
         }
         if (changed) {
            Log.d("x", "Change");
            gl = (GL10) mEglHelper.createSurface(pSv.mHolder);
            tellRendererSurfaceChanged = true;
         }
         if (tellRendererSurfaceCreated) {
            Log.d("x", "Render Surface created");
            mRenderer.surfaceCreated(gl);
            tellRendererSurfaceCreated = false;
         }
         if (tellRendererSurfaceChanged) {
            Log.d("x", "Render Surface changed");
            mRenderer.sizeChanged(gl, w, h);
            tellRendererSurfaceChanged = false;
         }
         if ((w > 0) && (h > 0)) {
            Log.d("x", "Drawing frame now");
            mRenderer.drawFrame(gl);
            mEglHelper.swap();
         }
      }
      mEglHelper.finish();
   }

   private boolean needToWait() {
      return ((!mSizeChanged) || 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;
         pSv.mSizeChanged = true;
         this.mSizeChanged = true;
         Log.d("x","window size changed. w, h:" + w + "," + h);
         if (w > 0)
         {
            notify();
         }
      }
   }

   public void requestExitAndWait()
   {
      synchronized(this) {
         mDone = true;
         notify();
      }
      try {
         join();
      } catch (InterruptedException ex) {
         Thread.currentThread().interrupt();
      }
   }
}

satya - Friday, June 12, 2009 11:29:52 PM

Listing 10-9. The EglHelper Class


//filename: EglHelper.java
public class EglHelper
{
   EGL10 mEgl; EGLDisplay mEglDisplay; EGLSurface mEglSurface;
   EGLConfig mEglConfig; EGLContext mEglContext;

   public EglHelper(){}

   public void start(int[] configSpec)
   {
      mEgl = (EGL10) EGLContext.getEGL();
      mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_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];

      mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig,
                                 EGL10.EGL_NO_CONTEXT, null);
      mEglSurface = null;
   }

   public GL createSurface(SurfaceHolder holder) {
      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);
      GL gl = mEglContext.getGL();
      return gl;
   }
   
   public boolean swap() {
      mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
      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;
      }
   }
}

satya - Friday, June 12, 2009 11:32:20 PM

Listing 10-10. The Methods of the Renderer Protocol


//filename: Renderer.java
public interface Renderer
{
   int[] getConfigSpec();
   void surfaceCreated(GL10 gl);
   void sizeChanged(GL10 gl, int width, int height);
   void drawFrame(GL10 gl);
}

satya - Friday, June 12, 2009 11:37:36 PM

Listing 10-11. The AbstractRenderer Class


//filename: AbstractRenderer.java
public abstract class AbstractRenderer implements Renderer
{
   public int[] getConfigSpec() {
      int[] configSpec = {
         EGL10.EGL_DEPTH_SIZE, 0,
         EGL10.EGL_NONE
      };
      return configSpec;
   }
   public void surfaceCreated(GL10 gl) {
      gl.glDisable(GL10.GL_DITHER);
      gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
                              GL10.GL_FASTEST);
      gl.glClearColor(.5f, .5f, .5f, 1);
      gl.glShadeModel(GL10.GL_SMOOTH);
      gl.glEnable(GL10.GL_DEPTH_TEST);
   }
   public void sizeChanged(GL10 gl, int w, int h) {
      gl.glViewport(0, 0, w, h);
      float ratio = (float) w / h;
      gl.glMatrixMode(GL10.GL_PROJECTION);
      gl.glLoadIdentity();
      gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);
   }
   public void drawFrame(GL10 gl)
   {
      gl.glDisable(GL10.GL_DITHER);
      gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
      gl.glMatrixMode(GL10.GL_MODELVIEW);
      gl.glLoadIdentity();
      GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
      gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
      draw(gl);
   }
   protected abstract void draw(GL10 gl);
}

satya - Friday, June 12, 2009 11:41:25 PM

Listing 10-12. Drawing a Simple Triangle


//filename: SimpleTriangleRenderer.java
public class SimpleTriangleRenderer extends AbstractRenderer
{
   //Number of points or vertices we want to use
   private final static int VERTS = 3;

   //A raw native buffer to hold the point coordinates
   private FloatBuffer mFVertexBuffer;

   //A raw native buffer to hold indices
   //allowing a reuse of points.
   private ShortBuffer mIndexBuffer;

   public SimpleTriangleRenderer(Context context)
   {
      ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
      vbb.order(ByteOrder.nativeOrder());
      mFVertexBuffer = vbb.asFloatBuffer();

      ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
      ibb.order(ByteOrder.nativeOrder());
      mIndexBuffer = ibb.asShortBuffer();

      float[] coords = {
         -0.5f, -0.5f, 0, // (x1,y1,z1)
         0.5f, -0.5f, 0,
         0.0f, 0.5f, 0
      };
      
      for (int i = 0; i < VERTS; i++) {
         for(int j = 0; j < 3; j++) {
         mFVertexBuffer.put(coords[i*3+j]);
         }
      }
      
      short[] myIndecesArray = {0,1,2};
      for (int i=0;i<3;i++)
      {
         mIndexBuffer.put(myIndecesArray[i]);
      }
      
      mFVertexBuffer.position(0);
      mIndexBuffer.position(0);
   }
   //overridden method
   protected void draw(GL10 gl)
   {
      gl.glColor4f(1.0f, 0, 0, 0.5f);
      gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
      gl.glDrawElements(GL10.GL_TRIANGLES, VERTS,
      GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
   }
}

satya - Friday, June 12, 2009 11:45:07 PM

Listing 10-13. The SimpleTriangleRenderer2 Class


//filename: SimpleTriangleRenderer2.java
public class SimpleTriangleRenderer2 extends AbstractRenderer
{
   private final static int VERTS = 4;
   private FloatBuffer mFVertexBuffer;
   private ShortBuffer mIndexBuffer;

   public SimpleTriangleRenderer2(Context context)
   {
      ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
      vbb.order(ByteOrder.nativeOrder());
      mFVertexBuffer = vbb.asFloatBuffer();
      ByteBuffer ibb = ByteBuffer.allocateDirect(6 * 2);
      ibb.order(ByteOrder.nativeOrder());
      mIndexBuffer = ibb.asShortBuffer();
      
      float[] coords = {
         -1.0f, -1.0f, 0, // (x1,y1,z1)
         1.0f, -1.0f, 0,
         0.0f, 1.0f, 0,
         1.0f, 1.0f, 0
      };

      for (int i = 0; i < VERTS; i++) {
         for(int j = 0; j < 3; j++) {
         mFVertexBuffer.put(coords[i*3+j]);
         }
      }

      short[] myIndecesArray = {0,1,2, 0,2,3};
      for (int i=0;i<6;i++)
      {
         mIndexBuffer.put(myIndecesArray[i]);
      }
      mFVertexBuffer.position(0);
      mIndexBuffer.position(0);
   }

   protected void draw(GL10 gl)
   {
      gl.glColor4f(1.0f, 0, 0, 0.5f);
      gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
      gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_SHORT,
      mIndexBuffer);
   }
}