diff options
Diffstat (limited to 'opengl/java/android/opengl/GLSurfaceView.java')
-rw-r--r-- | opengl/java/android/opengl/GLSurfaceView.java | 661 |
1 files changed, 0 insertions, 661 deletions
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java deleted file mode 100644 index 42c53f9..0000000 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ /dev/null @@ -1,661 +0,0 @@ -/* - * 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. - */ - -package android.opengl; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -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 android.content.Context; -import android.util.AttributeSet; -import android.util.Log; -import android.view.SurfaceHolder; -import android.view.SurfaceView; - -/** - * 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. - */ -public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback { - public final static int RENDERMODE_WHEN_DIRTY = 0; - public final static int RENDERMODE_CONTUOUSLY = 1; - - /** - * Check glError() after every GL call. - */ - public final static int DEBUG_CHECK_GL_ERROR = 1; - - /** - * Log GL calls to the system log at "verbose" level with tag "GLSurfaceView". - */ - public final static int DEBUG_LOG_GL_CALLS = 2; - - 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 - SurfaceHolder holder = getHolder(); - holder.addCallback(this); - holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); - } - - /** - * Set the glWrapper to a new value. The current glWrapper is used - * whenever a surface is created. The default value is null. - * @param glWrapper the new GLWrapper - */ - public void setGLWrapper(GLWrapper glWrapper) { - mGLWrapper = glWrapper; - } - - /** - * Set the debug flags to a new value. The debug flags take effect - * whenever a surface is created. The default value is zero. - * @param debugFlags the new debug flags - * @see #DEBUG_CHECK_GL_ERROR - * @see #DEBUG_LOG_GL_CALLS - */ - public void setDebugFlags(int debugFlags) { - mDebugFlags = debugFlags; - } - - public int getDebugFlags() { - return mDebugFlags; - } - - /** - * Set the renderer associated with this view. Can only be called once. - * @param renderer - */ - public void setRenderer(Renderer renderer) { - if (mGLThread != null) { - throw new IllegalStateException("setRenderer has already been called for this instance."); - } - mGLThread = new GLThread(renderer); - mGLThread.start(); - } - - /** - * Set the rendering mode. When the renderMode is - * RENDERMODE_CONTINUOUSLY, the renderer is called - * repeatedly to re-render the scene. When the rendermode - * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface - * is created, or when requestRender is called. Defaults to RENDERMODE_CONTINUOUSLY. - * @param renderMode one of the RENDERMODE_X constants - */ - public void setRenderMode(int renderMode) { - mGLThread.setRenderMode(renderMode); - } - - /** - * Get the current rendering mode. May be called - * from any thread. Must not be called before a renderer has been set. - * @return true if the renderer will render continuously. - */ - public int getRenderMode() { - return mGLThread.getRenderMode(); - } - - /** - * Request that the renderer render a frame. May be called - * from any thread. Must not be called before a renderer has been set. - * This method is typically used when the render mode has been set to - * false, so that frames are only rendered on demand. - */ - public void requestRender() { - mGLThread.requestRender(); - } - - 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) { - mGLThread.onWindowResize(w, h); - } - - /** - * Inform the view that the activity is paused. The owner of this view must - * call this method when the activity is paused. - */ - public void onPause() { - mGLThread.onPause(); - } - - /** - * Inform the view that the activity is resumed. The owner of this view must - * call this method when the activity is resumed. - */ - public void onResume() { - mGLThread.onResume(); - } - - /** - * 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 queueEvent(Runnable r) { - mGLThread.queueEvent(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. - * @param gl the GL interface. Use <code>instanceof</code> to - * test if the interface supports GL11 or higher interfaces. - * @param config the EGLConfig of the created surface. Can be used - * to create matching pbuffers. - */ - void onSurfaceCreated(GL10 gl, EGLConfig config); - /** - * Surface changed size. - * Called after the surface is created and whenever - * the OpenGL ES surface size changes. Set your viewport here. - * @param gl the GL interface. Use <code>instanceof</code> to - * test if the interface supports GL11 or higher interfaces. - * @param width - * @param height - */ - void onSurfaceChanged(GL10 gl, int width, int height); - /** - * Draw the current frame. - * @param gl the GL interface. Use <code>instanceof</code> to - * test if the interface supports GL11 or higher interfaces. - */ - void onDrawFrame(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; - } - - /* - * React to the creation of a new surface by creating and returning an - * OpenGL interface that renders to that 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); - } - - if ((mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS))!= 0) { - int configFlags = 0; - Writer log = null; - if ((mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) { - configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR; - } - if ((mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) { - log = new LogWriter(); - } - gl = GLDebugHelper.wrap(gl, configFlags, log); - } - 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. Can be configured to - * render continuously or on request. - * - */ - class GLThread extends Thread { - GLThread(Renderer renderer) { - super(); - mDone = false; - mWidth = 0; - mHeight = 0; - mRequestRender = true; - mRenderMode = RENDERMODE_CONTUOUSLY; - 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) { - Runnable r; - while ((r = getEvent()) != null) { - r.run(); - } - if (mPaused) { - mEglHelper.finish(); - needStart = true; - } - while (needToWait()) { - wait(); - } - if (mDone) { - break; - } - changed = mSizeChanged; - w = mWidth; - h = mHeight; - mSizeChanged = false; - mRequestRender = false; - } - if (needStart) { - mEglHelper.start(configSpec); - tellRendererSurfaceCreated = true; - changed = true; - } - if (changed) { - gl = (GL10) mEglHelper.createSurface(getHolder()); - tellRendererSurfaceChanged = true; - } - if (tellRendererSurfaceCreated) { - mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig); - tellRendererSurfaceCreated = false; - } - if (tellRendererSurfaceChanged) { - mRenderer.onSurfaceChanged(gl, w, h); - tellRendererSurfaceChanged = false; - } - if ((w > 0) && (h > 0)) { - /* draw a frame here */ - mRenderer.onDrawFrame(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... - */ - mEglHelper.finish(); - } - - private boolean needToWait() { - if (mDone) { - return false; - } - - if (mPaused || (! mHasSurface)) { - return true; - } - - if ((mWidth > 0) && (mHeight > 0) && (mRequestRender || (mRenderMode == RENDERMODE_CONTUOUSLY))) { - return false; - } - - return true; - } - - public void setRenderMode(int renderMode) { - if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTUOUSLY)) ) { - throw new IllegalArgumentException("renderMode"); - } - synchronized(this) { - mRenderMode = renderMode; - if (renderMode == RENDERMODE_CONTUOUSLY) { - notify(); - } - } - } - - public int getRenderMode() { - synchronized(this) { - return mRenderMode; - } - } - - public void requestRender() { - synchronized(this) { - mRequestRender = true; - notify(); - } - } - - public void surfaceCreated() { - synchronized(this) { - mHasSurface = true; - 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 onWindowResize(int w, int h) { - synchronized (this) { - mWidth = w; - mHeight = h; - mSizeChanged = true; - notify(); - } - } - - 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 queueEvent(Runnable r) { - synchronized(this) { - mEventQueue.add(r); - } - } - - private Runnable getEvent() { - synchronized(this) { - if (mEventQueue.size() > 0) { - return mEventQueue.remove(0); - } - - } - return null; - } - - private boolean mDone; - private boolean mPaused; - private boolean mHasSurface; - private int mWidth; - private int mHeight; - private int mRenderMode; - private boolean mRequestRender; - private Renderer mRenderer; - private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>(); - private EglHelper mEglHelper; - } - - static class LogWriter extends Writer { - - @Override public void close() { - flushBuilder(); - } - - @Override public void flush() { - flushBuilder(); - } - - @Override public void write(char[] buf, int offset, int count) { - for(int i = 0; i < count; i++) { - char c = buf[offset + i]; - if ( c == '\n') { - flushBuilder(); - } - else { - mBuilder.append(c); - } - } - } - - private void flushBuilder() { - if (mBuilder.length() > 0) { - Log.v("GLSurfaceView", mBuilder.toString()); - mBuilder.delete(0, mBuilder.length()); - } - } - - private StringBuilder mBuilder = new StringBuilder(); - } - - private static final Semaphore sEglSemaphore = new Semaphore(1); - private boolean mSizeChanged = true; - - private GLThread mGLThread; - private GLWrapper mGLWrapper; - private int mDebugFlags; -} |