package org.andengine.extension.opengl; 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 org.andengine.util.exception.AndEngineRuntimeException; import android.opengl.GLSurfaceView.EGLConfigChooser; import android.view.SurfaceHolder; /** * (c) Zynga 2011 * * @author Nicolas Gramlich <ngramlich@zynga.com> * @since 02:01:07 - 10.11.2011 */ public class EGLHelper { // =========================================================== // Constants // =========================================================== private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; private static final int[] EGL_ATTRIBUTES = { EGLHelper.EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; // =========================================================== // Fields // =========================================================== private EGL10 mEGL; private EGLDisplay mEGLDisplay; private EGLSurface mEGLSurface; private EGLContext mEGLContext; EGLConfig mEGLConfig; private final EGLConfigChooser mEGLConfigChooser; // =========================================================== // Constructors // =========================================================== public EGLHelper(final EGLConfigChooser pEGLConfigChooser) { this.mEGLConfigChooser = pEGLConfigChooser; } // =========================================================== // Getter & Setter // =========================================================== // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== // =========================================================== // Methods // =========================================================== public void start() { /* Get an EGL instance. */ this.mEGL = (EGL10) EGLContext.getEGL(); /* Get to the default display. */ this.mEGLDisplay = this.mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); /* We can now initialize EGL for that display. */ final int[] version = new int[2]; if(!this.mEGL.eglInitialize(this.mEGLDisplay, version)) { throw new AndEngineRuntimeException(EGLHelper.class.getSimpleName() + ".eglInitialize failed." + " @(Thread: '" + Thread.currentThread().getName() + "')"); } this.mEGLConfig = this.mEGLConfigChooser.chooseConfig(this.mEGL, this.mEGLDisplay); /* Create an OpenGL ES context. This must be done only once, an OpenGL context is a somewhat heavy object. */ this.mEGLContext = this.mEGL.eglCreateContext(this.mEGLDisplay, this.mEGLConfig, EGL10.EGL_NO_CONTEXT, EGLHelper.EGL_ATTRIBUTES); if (this.mEGLContext == null || this.mEGLContext == EGL10.EGL_NO_CONTEXT) { throw new RuntimeException("createContext failed"); } this.mEGLSurface = null; } /** * React to the creation of a new surface by creating and returning an * OpenGL interface that renders to that surface. */ public GL createSurface(final SurfaceHolder pSurfaceHolder) { /* The window size has changed, so we need to create a new surface. */ if (this.mEGLSurface != null && this.mEGLSurface != EGL10.EGL_NO_SURFACE) { /* Unbind and destroy the old EGL surface, if there is one. */ this.mEGL.eglMakeCurrent(this.mEGLDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); this.mEGL.eglDestroySurface(this.mEGLDisplay, this.mEGLSurface); } /* Create an EGL surface we can render into. */ this.mEGLSurface = this.mEGL.eglCreateWindowSurface(this.mEGLDisplay, this.mEGLConfig, pSurfaceHolder, null); if (this.mEGLSurface == null || this.mEGLSurface == EGL10.EGL_NO_SURFACE) { throw new RuntimeException("createSurface failed"); } /* Before we can issue GL commands, we need to make sure the context is current and bound to a surface. */ if (!this.mEGL.eglMakeCurrent(this.mEGLDisplay, this.mEGLSurface, this.mEGLSurface, this.mEGLContext)) { throw new RuntimeException("eglMakeCurrent failed."); } return this.mEGLContext.getGL(); } /** * Display the current render surface. * * @return false if the context has been lost. */ public boolean swapBuffers() { this.mEGL.eglSwapBuffers(this.mEGLDisplay, this.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 this.mEGL.eglGetError() != EGL11.EGL_CONTEXT_LOST; } public void destroySurface() { if (this.mEGLSurface != null && this.mEGLSurface != EGL10.EGL_NO_SURFACE) { this.mEGL.eglMakeCurrent(this.mEGLDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); this.mEGL.eglDestroySurface(this.mEGLDisplay, this.mEGLSurface); this.mEGLSurface = null; } } public void finish() { if (this.mEGLContext != null) { this.mEGL.eglDestroyContext(this.mEGLDisplay, this.mEGLContext); this.mEGLContext = null; } if (this.mEGLDisplay != null) { this.mEGL.eglTerminate(this.mEGLDisplay); this.mEGLDisplay = null; } } // =========================================================== // Inner and Anonymous Classes // =========================================================== }