diff --git a/alienblaster/project/src/GLSurfaceView_SDL.java b/alienblaster/project/src/GLSurfaceView_SDL.java index 6567ddeff..4c9067afb 100644 --- a/alienblaster/project/src/GLSurfaceView_SDL.java +++ b/alienblaster/project/src/GLSurfaceView_SDL.java @@ -897,6 +897,7 @@ public class GLSurfaceView_SDL extends SurfaceView implements SurfaceHolder.Call mEglHelper = new EglHelper(); // mEglHelper.start(); mNeedStart = true; + mSizeChanged = true; SwapBuffers(); SwapBuffers(); @@ -955,6 +956,7 @@ public class GLSurfaceView_SDL extends SurfaceView implements SurfaceHolder.Call mEglHelper.start(); tellRendererSurfaceCreated = true; changed = true; + mNeedStart = false; } if (changed) { mGL = (GL10) mEglHelper.createSurface(getHolder()); diff --git a/alienblaster/project/src_1.6/GLSurfaceView_SDL.java b/alienblaster/project/src_1.6/GLSurfaceView_SDL.java deleted file mode 100644 index 6567ddeff..000000000 --- a/alienblaster/project/src_1.6/GLSurfaceView_SDL.java +++ /dev/null @@ -1,1146 +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. - */ - -/* This is GLSurfaceView class ripped out of Android 2.1 sources, - fixed with a hammer and rasp to work with libSDL port */ - -// This string is autogenerated by ChangeAppSettings.sh, do not change spaces amount -package com.demo.glxgears; - -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 OpenGL rendering. - *
- * A GLSurfaceView provides the following features: - *
- *
- * Typically you use GLSurfaceView by subclassing it and overriding one or more of the - * View system input event methods. If your application does not need to override event - * methods then GLSurfaceView can be used as-is. For the most part - * GLSurfaceView behavior is customized by calling "set" methods rather than by subclassing. - * For example, unlike a regular View, drawing is delegated to a separate Renderer object which - * is registered with the GLSurfaceView - * using the {@link #setRenderer(Renderer)} call. - *
- *
- *
- * By default GLSurfaceView chooses an available surface that's closest to a 16-bit R5G6B5 surface - * with a 16-bit depth buffer and no stencil. If you would prefer a different surface (for example, - * if you do not need a depth buffer) you can override the default behavior by calling one of the - * setEGLConfigChooser methods. - *
- *
- *
- *
- *
- *
- * To handle an event you will typically subclass GLSurfaceView and override the - * appropriate method, just as you would with any other View. However, when handling - * the event, you may need to communicate with the Renderer object - * that's running in the rendering thread. You can do this using any - * standard Java cross-thread communication mechanism. In addition, - * one relatively easy way to communicate with your renderer is - * to call - * {@link #queueEvent(Runnable)}. For example: - *
- * class MyGLSurfaceView extends GLSurfaceView {
- *
- * private MyRenderer mMyRenderer;
- *
- * public void start() {
- * mMyRenderer = ...;
- * setRenderer(mMyRenderer);
- * }
- *
- * public boolean onKeyDown(int keyCode, KeyEvent event) {
- * if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
- * queueEvent(new Runnable() {
- * // This method will be called on the rendering
- * // thread:
- * public void run() {
- * mMyRenderer.handleDpadCenter();
- * }});
- * return true;
- * }
- * return super.onKeyDown(keyCode, event);
- * }
- * }
- *
- *
- */
-public class GLSurfaceView_SDL extends SurfaceView implements SurfaceHolder.Callback {
- /**
- * The renderer only renders
- * when the surface is created, or when {@link #requestRender} is called.
- *
- * @see #getRenderMode()
- * @see #setRenderMode(int)
- */
- public final static int RENDERMODE_WHEN_DIRTY = 0;
- /**
- * The renderer is called
- * continuously to re-render the scene.
- *
- * @see #getRenderMode()
- * @see #setRenderMode(int)
- * @see #requestRender()
- */
- public final static int RENDERMODE_CONTINUOUSLY = 1;
-
- /**
- * Check glError() after every GL call and throw an exception if glError indicates
- * that an error has occurred. This can be used to help track down which OpenGL ES call
- * is causing an error.
- *
- * @see #getDebugFlags
- * @see #setDebugFlags
- */
- public final static int DEBUG_CHECK_GL_ERROR = 1;
-
- /**
- * Log GL calls to the system log at "verbose" level with tag "GLSurfaceView".
- *
- * @see #getDebugFlags
- * @see #setDebugFlags
- */
- public final static int DEBUG_LOG_GL_CALLS = 2;
-
- /**
- * Standard View constructor. In order to render something, you
- * must call {@link #setRenderer} to register a renderer.
- */
- public GLSurfaceView_SDL(Context context) {
- super(context);
- init();
- }
-
- /**
- * Standard View constructor. In order to render something, you
- * must call {@link #setRenderer} to register a renderer.
- */
- public GLSurfaceView_SDL(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. If the glWrapper is not null, its
- * {@link GLWrapper#wrap(GL)} method is called
- * whenever a surface is created. A GLWrapper can be used to wrap
- * the GL object that's passed to the renderer. Wrapping a GL
- * object enables examining and modifying the behavior of the
- * GL calls made by the renderer.
- * - * Wrapping is typically used for debugging purposes. - *
- * 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 value is - * constructed by OR-together zero or more - * of the DEBUG_CHECK_* constants. 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; - } - - /** - * Get the current value of the debug flags. - * @return the current value of the debug flags. - */ - public int getDebugFlags() { - return mDebugFlags; - } - - /** - * Set the renderer associated with this view. Also starts the thread that - * will call the renderer, which in turn causes the rendering to start. - *
This method should be called once and only once in the life-cycle of - * a GLSurfaceView. - *
The following GLSurfaceView methods can only be called before - * setRenderer is called: - *
- * The following GLSurfaceView methods can only be called after - * setRenderer is called: - *
If this method is - * called, it must be called before {@link #setRenderer(Renderer)} - * is called. - *
- * If no setEGLConfigChooser method is called, then by default the - * view will choose a config as close to 16-bit RGB as possible, with - * a depth buffer as close to 16 bits as possible. - * @param configChooser - */ - public void setEGLConfigChooser(EGLConfigChooser configChooser) { - if (mGLThread != null) { - throw new IllegalStateException( - "setRenderer has already been called for this instance."); - } - mEGLConfigChooser = configChooser; - } - - /** - * Install a config chooser which will choose a config - * as close to 16-bit RGB as possible, with or without an optional depth - * buffer as close to 16-bits as possible. - *
If this method is - * called, it must be called before {@link #setRenderer(Renderer)} - * is called. - *
- * If no setEGLConfigChooser method is called, then by default the - * view will choose a config as close to 16-bit RGB as possible, with - * a depth buffer as close to 16 bits as possible. - * - * @param needDepth - */ - public void setEGLConfigChooser(boolean needDepth) { - setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth)); - } - - /** - * Install a config chooser which will choose a config - * with at least the specified component sizes, and as close - * to the specified component sizes as possible. - *
If this method is - * called, it must be called before {@link #setRenderer(Renderer)} - * is called. - *
- * If no setEGLConfigChooser method is called, then by default the - * view will choose a config as close to 16-bit RGB as possible, with - * a depth buffer as close to 16 bits as possible. - * - */ - public void setEGLConfigChooser(int redSize, int greenSize, int blueSize, - int alphaSize, int depthSize, int stencilSize) { - setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize, - blueSize, alphaSize, depthSize, stencilSize)); - } - /** - * Set the rendering mode. When renderMode is - * RENDERMODE_CONTINUOUSLY, the renderer is called - * repeatedly to re-render the scene. When renderMode - * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface - * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY. - *
- * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance - * by allowing the GPU and CPU to idle when the view does not need to be updated. - *
- * This method can only be called after {@link #setRenderer(Renderer)} - * - * @param renderMode one of the RENDERMODE_X constants - * @see #RENDERMODE_CONTINUOUSLY - * @see #RENDERMODE_WHEN_DIRTY - */ - 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 the current rendering mode. - * @see #RENDERMODE_CONTINUOUSLY - * @see #RENDERMODE_WHEN_DIRTY - */ - public int getRenderMode() { - return mGLThread.getRenderMode(); - } - - /** - * Request that the renderer render a frame. - * This method is typically used when the render mode has been set to - * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand. - * May be called - * from any thread. Must not be called before a renderer has been set. - */ - public void requestRender() { - mGLThread.requestRender(); - } - - /** - * This method is part of the SurfaceHolder.Callback interface, and is - * not normally called or subclassed by clients of GLSurfaceView. - */ - public void surfaceCreated(SurfaceHolder holder) { - mGLThread.surfaceCreated(); - } - - /** - * This method is part of the SurfaceHolder.Callback interface, and is - * not normally called or subclassed by clients of GLSurfaceView. - */ - public void surfaceDestroyed(SurfaceHolder holder) { - // Surface will be destroyed when we return - mGLThread.surfaceDestroyed(); - } - - /** - * This method is part of the SurfaceHolder.Callback interface, and is - * not normally called or subclassed by clients of GLSurfaceView. - */ - 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. Calling this method will - * pause the rendering thread. - * Must not be called before a renderer has been set. - */ - 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. Calling this method will - * recreate the OpenGL display and resume the rendering - * thread. - * Must not be called before a renderer has been set. - */ - public void onResume() { - mGLThread.onResume(); - } - - /** - * Queue a runnable to be run on the GL rendering thread. This can be used - * to communicate with the Renderer on the rendering thread. - * Must not be called before a renderer has been set. - * @param r the runnable to be run on the GL rendering thread. - */ - public void queueEvent(Runnable r) { - mGLThread.queueEvent(r); - } - - /** - * This method is used as part of the View class and is not normally - * called or subclassed by clients of GLSurfaceView. - * Must not be called before a renderer has been set. - */ - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mGLThread.requestExitAndWait(); - } - - // ---------------------------------------------------------------------- - - /** - * An interface used to wrap a GL interface. - *
Typically - * used for implementing debugging and tracing on top of the default - * GL interface. You would typically use this by creating your own class - * that implemented all the GL methods by delegating to another GL instance. - * Then you could add your own behavior before or after calling the - * delegate. All the GLWrapper would do was instantiate and return the - * wrapper GL instance: - *
- * class MyGLWrapper implements GLWrapper {
- * GL wrap(GL gl) {
- * return new MyGLImplementation(gl);
- * }
- * static class MyGLImplementation implements GL,GL10,GL11,... {
- * ...
- * }
- * }
- *
- * @see #setGLWrapper(GLWrapper)
- */
- public interface GLWrapper {
- /**
- * Wraps a gl interface in another gl interface.
- * @param gl a GL interface that is to be wrapped.
- * @return either the input argument or another GL object that wraps the input argument.
- */
- GL wrap(GL gl);
- }
-
- /**
- * A generic renderer interface.
- * - * The renderer is responsible for making OpenGL calls to render a frame. - *
- * GLSurfaceView clients typically create their own classes that implement - * this interface, and then call {@link GLSurfaceView#setRenderer} to - * register the renderer with the GLSurfaceView. - *
- *
- *
- * Called when the rendering thread - * starts and whenever the EGL context is lost. The context will typically - * be lost when the Android device awakes after going to sleep. - *
- * Since this method is called at the beginning of rendering, as well as - * every time the EGL context is lost, this method is a convenient place to put - * code to create resources that need to be created when the rendering - * starts, and that need to be recreated when the EGL context is lost. - * Textures are an example of a resource that you might want to create - * here. - *
- * Note that when the EGL context is lost, all OpenGL resources associated - * with that context will be automatically deleted. You do not need to call - * the corresponding "glDelete" methods such as glDeleteTextures to - * manually delete these lost resources. - *
- * @param gl the GL interface. Use instanceof 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.
- */
- public abstract void onSurfaceCreated(GL10 gl, EGLConfig config);
-
- /**
- * Called when the surface changed size.
- *
- * Called after the surface is created and whenever - * the OpenGL ES surface size changes. - *
- * Typically you will set your viewport here. If your camera - * is fixed then you could also set your projection matrix here: - *
- * void onSurfaceChanged(GL10 gl, int width, int height) {
- * gl.glViewport(0, 0, width, height);
- * // for a fixed camera, set the projection too
- * float ratio = (float) width / height;
- * gl.glMatrixMode(GL10.GL_PROJECTION);
- * gl.glLoadIdentity();
- * gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
- * }
- *
- * @param gl the GL interface. Use instanceof to
- * test if the interface supports GL11 or higher interfaces.
- * @param width
- * @param height
- */
- public abstract void onSurfaceChanged(GL10 gl, int width, int height);
-
- /**
- * Called to draw the current frame.
- * - * This method is responsible for drawing the current frame. - *
- * The implementation of this method typically looks like this: - *
- * void onDrawFrame(GL10 gl) {
- * gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
- * //... other gl calls to render the scene ...
- * }
- *
- * @param gl the GL interface. Use instanceof to
- * test if the interface supports GL11 or higher interfaces.
- */
- public abstract void onDrawFrame(GL10 gl);
-
- public boolean SwapBuffers() {
- if( mSwapBuffersCallback != null )
- return mSwapBuffersCallback.SwapBuffers();
- return false;
- }
-
- public void setSwapBuffersCallback( SwapBuffersCallback c ) {
- mSwapBuffersCallback = c;
- }
-
- private SwapBuffersCallback mSwapBuffersCallback = null;
- }
-
- /**
- * An interface for choosing an EGLConfig configuration from a list of
- * potential configurations.
- *
- * This interface must be implemented by clients wishing to call
- * {@link GLSurfaceView#setEGLConfigChooser(EGLConfigChooser)}
- */
- public interface EGLConfigChooser {
- /**
- * Choose a configuration from the list. Implementors typically
- * implement this method by calling
- * {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the
- * EGL specification available from The Khronos Group to learn how to call eglChooseConfig.
- * @param egl the EGL10 for the current display.
- * @param display the current display.
- * @return the chosen configuration.
- */
- EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
- }
-
- private static abstract class BaseConfigChooser
- implements EGLConfigChooser {
- public BaseConfigChooser(int[] configSpec) {
- mConfigSpec = configSpec;
- }
- public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
- int[] num_config = new int[1];
- egl.eglChooseConfig(display, mConfigSpec, null, 0, num_config);
-
- int numConfigs = num_config[0];
-
- if (numConfigs <= 0) {
- throw new IllegalArgumentException(
- "No configs match configSpec");
- }
-
- EGLConfig[] configs = new EGLConfig[numConfigs];
- egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
- num_config);
- EGLConfig config = chooseConfig(egl, display, configs);
- if (config == null) {
- throw new IllegalArgumentException("No config chosen");
- }
- return config;
- }
-
- abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
- EGLConfig[] configs);
-
- protected int[] mConfigSpec;
- }
-
- private static class ComponentSizeChooser extends BaseConfigChooser {
- public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
- int alphaSize, int depthSize, int stencilSize) {
- super(new int[] {
- EGL10.EGL_RED_SIZE, redSize,
- EGL10.EGL_GREEN_SIZE, greenSize,
- EGL10.EGL_BLUE_SIZE, blueSize,
- EGL10.EGL_ALPHA_SIZE, alphaSize,
- EGL10.EGL_DEPTH_SIZE, depthSize,
- EGL10.EGL_STENCIL_SIZE, stencilSize,
- EGL10.EGL_NONE});
- mValue = new int[1];
- mRedSize = redSize;
- mGreenSize = greenSize;
- mBlueSize = blueSize;
- mAlphaSize = alphaSize;
- mDepthSize = depthSize;
- mStencilSize = stencilSize;
- }
-
- @Override
- public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
- EGLConfig[] configs) {
- EGLConfig closestConfig = null;
- int closestDistance = 1000;
- for(EGLConfig config : configs) {
- int r = findConfigAttrib(egl, display, config,
- EGL10.EGL_RED_SIZE, 0);
- int g = findConfigAttrib(egl, display, config,
- EGL10.EGL_GREEN_SIZE, 0);
- int b = findConfigAttrib(egl, display, config,
- EGL10.EGL_BLUE_SIZE, 0);
- int a = findConfigAttrib(egl, display, config,
- EGL10.EGL_ALPHA_SIZE, 0);
- int d = findConfigAttrib(egl, display, config,
- EGL10.EGL_DEPTH_SIZE, 0);
- int s = findConfigAttrib(egl, display, config,
- EGL10.EGL_STENCIL_SIZE, 0);
- int distance = Math.abs(r - mRedSize)
- + Math.abs(g - mGreenSize)
- + Math.abs(b - mBlueSize) + Math.abs(a - mAlphaSize)
- + Math.abs(d - mDepthSize) + Math.abs(s - mStencilSize);
- if (distance < closestDistance) {
- closestDistance = distance;
- closestConfig = config;
- }
- }
- return closestConfig;
- }
-
- private int findConfigAttrib(EGL10 egl, EGLDisplay display,
- EGLConfig config, int attribute, int defaultValue) {
-
- if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
- return mValue[0];
- }
- return defaultValue;
- }
-
- private int[] mValue;
- // Subclasses can adjust these values:
- protected int mRedSize;
- protected int mGreenSize;
- protected int mBlueSize;
- protected int mAlphaSize;
- protected int mDepthSize;
- protected int mStencilSize;
- }
-
- /**
- * This class will choose a supported surface as close to
- * RGB565 as possible, with or without a depth buffer.
- *
- */
- private static class SimpleEGLConfigChooser extends ComponentSizeChooser {
- public SimpleEGLConfigChooser(boolean withDepthBuffer) {
- super(4, 4, 4, 0, withDepthBuffer ? 16 : 0, 0);
- // Adjust target values. This way we'll accept a 4444 or
- // 555 buffer if there's no 565 buffer available.
- mRedSize = 5;
- mGreenSize = 6;
- mBlueSize = 5;
- }
- }
-
- /**
- * An EGL helper class.
- */
-
- private class EglHelper {
- public EglHelper() {
-
- }
-
- /**
- * Initialize EGL for a given configuration spec.
- * @param configSpec
- */
- public void start(){
- /*
- * 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);
- mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
-
- /*
- * 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);
- }
-
- 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 implements SwapBuffersCallback {
- GLThread(Renderer renderer) {
- super();
- mDone = false;
- mWidth = 0;
- mHeight = 0;
- mRequestRender = true;
- mRenderMode = RENDERMODE_CONTINUOUSLY;
- mRenderer = renderer;
- mRenderer.setSwapBuffersCallback(this);
- 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 {
- sEglSemaphore.acquire();
- } catch (InterruptedException e) {
- return;
- }
-
- mEglHelper = new EglHelper();
- // mEglHelper.start();
- mNeedStart = true;
- SwapBuffers();
- SwapBuffers();
-
- mRenderer.onDrawFrame(mGL);
-
- mEglHelper.finish();
-
- /*
- synchronized (sGLThreadManager) {
- stopEglLocked();
- }
- sGLThreadManager.threadExiting(this);
- */
-
- sEglSemaphore.release();
- }
-
- public boolean SwapBuffers() {
-
- boolean tellRendererSurfaceCreated = false;
- boolean tellRendererSurfaceChanged = false;
-
- /*
- * This is our main activity thread's loop, we go until
- * asked to quit.
- */
- try {
-
- /*
- * Update the asynchronous state (window size)
- */
- int w, h;
- boolean changed;
- synchronized (this) {
- Runnable r;
- while ((r = getEvent()) != null) {
- r.run();
- }
- if (mPaused) {
- mEglHelper.finish();
- mNeedStart = true;
- }
- while (needToWait()) {
- wait();
- }
- if (mDone) {
- return false;
- }
- changed = mSizeChanged;
- w = mWidth;
- h = mHeight;
- mSizeChanged = false;
- mRequestRender = false;
- }
- if (mNeedStart) {
- mEglHelper.start();
- tellRendererSurfaceCreated = true;
- changed = true;
- }
- if (changed) {
- mGL = (GL10) mEglHelper.createSurface(getHolder());
- tellRendererSurfaceChanged = true;
- }
- if (tellRendererSurfaceCreated) {
- mRenderer.onSurfaceCreated(mGL, mEglHelper.mEglConfig);
- tellRendererSurfaceCreated = false;
- }
- if (tellRendererSurfaceChanged) {
- mRenderer.onSurfaceChanged(mGL, w, h);
- tellRendererSurfaceChanged = false;
- }
- /*
- * Once we're done with GL, we need to call swapBuffers()
- * to instruct the system to display the rendered frame
- */
- return mEglHelper.swap();
-
- } catch (java.lang.InterruptedException e) {
- return false;
- }
- }
-
- private boolean needToWait() {
- if (mDone) {
- return false;
- }
-
- if (mPaused || (! mHasSurface)) {
- return true;
- }
-
- if ((mWidth > 0) && (mHeight > 0) && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) {
- return false;
- }
-
- return true;
- }
-
- public void setRenderMode(int renderMode) {
- if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) {
- throw new IllegalArgumentException("renderMode");
- }
- synchronized(this) {
- mRenderMode = renderMode;
- if (renderMode == RENDERMODE_CONTINUOUSLY) {
- 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
- * A GLSurfaceView provides the following features:
- *
- *
- * Typically you use GLSurfaceView by subclassing it and overriding one or more of the
- * View system input event methods. If your application does not need to override event
- * methods then GLSurfaceView can be used as-is. For the most part
- * GLSurfaceView behavior is customized by calling "set" methods rather than by subclassing.
- * For example, unlike a regular View, drawing is delegated to a separate Renderer object which
- * is registered with the GLSurfaceView
- * using the {@link #setRenderer(Renderer)} call.
- *
- *
- *
- * By default GLSurfaceView chooses an available surface that's closest to a 16-bit R5G6B5 surface
- * with a 16-bit depth buffer and no stencil. If you would prefer a different surface (for example,
- * if you do not need a depth buffer) you can override the default behavior by calling one of the
- * setEGLConfigChooser methods.
- *
- *
- *
- *
- *
- *
- * To handle an event you will typically subclass GLSurfaceView and override the
- * appropriate method, just as you would with any other View. However, when handling
- * the event, you may need to communicate with the Renderer object
- * that's running in the rendering thread. You can do this using any
- * standard Java cross-thread communication mechanism. In addition,
- * one relatively easy way to communicate with your renderer is
- * to call
- * {@link #queueEvent(Runnable)}. For example:
- *
- * Wrapping is typically used for debugging purposes.
- *
- * 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 value is
- * constructed by OR-together zero or more
- * of the DEBUG_CHECK_* constants. 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;
- }
-
- /**
- * Get the current value of the debug flags.
- * @return the current value of the debug flags.
- */
- public int getDebugFlags() {
- return mDebugFlags;
- }
-
- /**
- * Set the renderer associated with this view. Also starts the thread that
- * will call the renderer, which in turn causes the rendering to start.
- * This method should be called once and only once in the life-cycle of
- * a GLSurfaceView.
- * The following GLSurfaceView methods can only be called before
- * setRenderer is called:
- *
- * The following GLSurfaceView methods can only be called after
- * setRenderer is called:
- * If this method is
- * called, it must be called before {@link #setRenderer(Renderer)}
- * is called.
- *
- * If this method is not called, then by default
- * a context will be created with no shared context and
- * with a null attribute list.
- */
- public void setEGLContextFactory(EGLContextFactory factory) {
- checkRenderThreadState();
- mEGLContextFactory = factory;
- }
-
- /**
- * Install a custom EGLWindowSurfaceFactory.
- * If this method is
- * called, it must be called before {@link #setRenderer(Renderer)}
- * is called.
- *
- * If this method is not called, then by default
- * a window surface will be created with a null attribute list.
- */
- public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) {
- checkRenderThreadState();
- mEGLWindowSurfaceFactory = factory;
- }
-
- /**
- * Install a custom EGLConfigChooser.
- * If this method is
- * called, it must be called before {@link #setRenderer(Renderer)}
- * is called.
- *
- * If no setEGLConfigChooser method is called, then by default the
- * view will choose a config as close to 16-bit RGB as possible, with
- * a depth buffer as close to 16 bits as possible.
- * @param configChooser
- */
- public void setEGLConfigChooser(EGLConfigChooser configChooser) {
- checkRenderThreadState();
- mEGLConfigChooser = configChooser;
- }
-
- /**
- * Install a config chooser which will choose a config
- * as close to 16-bit RGB as possible, with or without an optional depth
- * buffer as close to 16-bits as possible.
- * If this method is
- * called, it must be called before {@link #setRenderer(Renderer)}
- * is called.
- *
- * If no setEGLConfigChooser method is called, then by default the
- * view will choose a config as close to 16-bit RGB as possible, with
- * a depth buffer as close to 16 bits as possible.
- *
- * @param needDepth
- */
- public void setEGLConfigChooser(boolean needDepth) {
- setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));
- }
-
- /**
- * Install a config chooser which will choose a config
- * with at least the specified component sizes, and as close
- * to the specified component sizes as possible.
- * If this method is
- * called, it must be called before {@link #setRenderer(Renderer)}
- * is called.
- *
- * If no setEGLConfigChooser method is called, then by default the
- * view will choose a config as close to 16-bit RGB as possible, with
- * a depth buffer as close to 16 bits as possible.
- *
- */
- public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
- int alphaSize, int depthSize, int stencilSize) {
- setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize,
- blueSize, alphaSize, depthSize, stencilSize));
- }
- /**
- * Set the rendering mode. When renderMode is
- * RENDERMODE_CONTINUOUSLY, the renderer is called
- * repeatedly to re-render the scene. When renderMode
- * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface
- * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY.
- *
- * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance
- * by allowing the GPU and CPU to idle when the view does not need to be updated.
- *
- * This method can only be called after {@link #setRenderer(Renderer)}
- *
- * @param renderMode one of the RENDERMODE_X constants
- * @see #RENDERMODE_CONTINUOUSLY
- * @see #RENDERMODE_WHEN_DIRTY
- */
- 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 the current rendering mode.
- * @see #RENDERMODE_CONTINUOUSLY
- * @see #RENDERMODE_WHEN_DIRTY
- */
- public int getRenderMode() {
- return mGLThread.getRenderMode();
- }
-
- /**
- * Request that the renderer render a frame.
- * This method is typically used when the render mode has been set to
- * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand.
- * May be called
- * from any thread. Must not be called before a renderer has been set.
- */
- public void requestRender() {
- mGLThread.requestRender();
- }
-
- /**
- * This method is part of the SurfaceHolder.Callback interface, and is
- * not normally called or subclassed by clients of GLSurfaceView.
- */
- public void surfaceCreated(SurfaceHolder holder) {
- mGLThread.surfaceCreated();
- }
-
- /**
- * This method is part of the SurfaceHolder.Callback interface, and is
- * not normally called or subclassed by clients of GLSurfaceView.
- */
- public void surfaceDestroyed(SurfaceHolder holder) {
- // Surface will be destroyed when we return
- mGLThread.surfaceDestroyed();
- }
-
- /**
- * This method is part of the SurfaceHolder.Callback interface, and is
- * not normally called or subclassed by clients of GLSurfaceView.
- */
- 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. Calling this method will
- * pause the rendering thread.
- * Must not be called before a renderer has been set.
- */
- 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. Calling this method will
- * recreate the OpenGL display and resume the rendering
- * thread.
- * Must not be called before a renderer has been set.
- */
- public void onResume() {
- mGLThread.onResume();
- }
-
- /**
- * Queue a runnable to be run on the GL rendering thread. This can be used
- * to communicate with the Renderer on the rendering thread.
- * Must not be called before a renderer has been set.
- * @param r the runnable to be run on the GL rendering thread.
- */
- public void queueEvent(Runnable r) {
- mGLThread.queueEvent(r);
- }
-
- /**
- * This method is used as part of the View class and is not normally
- * called or subclassed by clients of GLSurfaceView.
- * Must not be called before a renderer has been set.
- */
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mGLThread.requestExitAndWait();
- }
-
- // ----------------------------------------------------------------------
-
- /**
- * An interface used to wrap a GL interface.
- * Typically
- * used for implementing debugging and tracing on top of the default
- * GL interface. You would typically use this by creating your own class
- * that implemented all the GL methods by delegating to another GL instance.
- * Then you could add your own behavior before or after calling the
- * delegate. All the GLWrapper would do was instantiate and return the
- * wrapper GL instance:
- *
- * The renderer is responsible for making OpenGL calls to render a frame.
- *
- * GLSurfaceView clients typically create their own classes that implement
- * this interface, and then call {@link GLSurfaceView#setRenderer} to
- * register the renderer with the GLSurfaceView.
- *
- *
- *
- * Called when the rendering thread
- * starts and whenever the EGL context is lost. The context will typically
- * be lost when the Android device awakes after going to sleep.
- *
- * Since this method is called at the beginning of rendering, as well as
- * every time the EGL context is lost, this method is a convenient place to put
- * code to create resources that need to be created when the rendering
- * starts, and that need to be recreated when the EGL context is lost.
- * Textures are an example of a resource that you might want to create
- * here.
- *
- * Note that when the EGL context is lost, all OpenGL resources associated
- * with that context will be automatically deleted. You do not need to call
- * the corresponding "glDelete" methods such as glDeleteTextures to
- * manually delete these lost resources.
- *
- * @param gl the GL interface. Use
- * Called after the surface is created and whenever
- * the OpenGL ES surface size changes.
- *
- * Typically you will set your viewport here. If your camera
- * is fixed then you could also set your projection matrix here:
- *
- * This method is responsible for drawing the current frame.
- *
- * The implementation of this method typically looks like this:
- *
- * This interface must be implemented by clients wishing to call
- * {@link GLSurfaceView#setEGLContextFactory(EGLContextFactory)}
- */
- public interface EGLContextFactory {
- EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig);
- void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
- }
-
- private static class DefaultContextFactory implements EGLContextFactory {
-
- public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
- return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, null);
- }
-
- public void destroyContext(EGL10 egl, EGLDisplay display,
- EGLContext context) {
- egl.eglDestroyContext(display, context);
- }
- }
-
- /**
- * An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls.
- *
- * This interface must be implemented by clients wishing to call
- * {@link GLSurfaceView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
- */
- public interface EGLWindowSurfaceFactory {
- EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config,
- Object nativeWindow);
- void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
- }
-
- private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {
-
- public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
- EGLConfig config, Object nativeWindow) {
- return egl.eglCreateWindowSurface(display, config, nativeWindow, null);
- }
-
- public void destroySurface(EGL10 egl, EGLDisplay display,
- EGLSurface surface) {
- egl.eglDestroySurface(display, surface);
- }
- }
-
- /**
- * An interface for choosing an EGLConfig configuration from a list of
- * potential configurations.
- *
- * This interface must be implemented by clients wishing to call
- * {@link GLSurfaceView#setEGLConfigChooser(EGLConfigChooser)}
- */
- public interface EGLConfigChooser {
- /**
- * Choose a configuration from the list. Implementors typically
- * implement this method by calling
- * {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the
- * EGL specification available from The Khronos Group to learn how to call eglChooseConfig.
- * @param egl the EGL10 for the current display.
- * @param display the current display.
- * @return the chosen configuration.
- */
- EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
- }
-
- private static abstract class BaseConfigChooser
- implements EGLConfigChooser {
- public BaseConfigChooser(int[] configSpec) {
- mConfigSpec = configSpec;
- }
- public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
- int[] num_config = new int[1];
- egl.eglChooseConfig(display, mConfigSpec, null, 0, num_config);
-
- int numConfigs = num_config[0];
-
- if (numConfigs <= 0) {
- throw new IllegalArgumentException(
- "No configs match configSpec");
- }
-
- EGLConfig[] configs = new EGLConfig[numConfigs];
- egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
- num_config);
- EGLConfig config = chooseConfig(egl, display, configs);
- if (config == null) {
- throw new IllegalArgumentException("No config chosen");
- }
- return config;
- }
-
- abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
- EGLConfig[] configs);
-
- protected int[] mConfigSpec;
- }
-
- private static class ComponentSizeChooser extends BaseConfigChooser {
- public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
- int alphaSize, int depthSize, int stencilSize) {
- super(new int[] {
- EGL10.EGL_RED_SIZE, redSize,
- EGL10.EGL_GREEN_SIZE, greenSize,
- EGL10.EGL_BLUE_SIZE, blueSize,
- EGL10.EGL_ALPHA_SIZE, alphaSize,
- EGL10.EGL_DEPTH_SIZE, depthSize,
- EGL10.EGL_STENCIL_SIZE, stencilSize,
- EGL10.EGL_NONE});
- mValue = new int[1];
- mRedSize = redSize;
- mGreenSize = greenSize;
- mBlueSize = blueSize;
- mAlphaSize = alphaSize;
- mDepthSize = depthSize;
- mStencilSize = stencilSize;
- }
-
- @Override
- public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
- EGLConfig[] configs) {
- EGLConfig closestConfig = null;
- int closestDistance = 1000;
- for(EGLConfig config : configs) {
- int d = findConfigAttrib(egl, display, config,
- EGL10.EGL_DEPTH_SIZE, 0);
- int s = findConfigAttrib(egl, display, config,
- EGL10.EGL_STENCIL_SIZE, 0);
- if (d >= mDepthSize && s>= mStencilSize) {
- int r = findConfigAttrib(egl, display, config,
- EGL10.EGL_RED_SIZE, 0);
- int g = findConfigAttrib(egl, display, config,
- EGL10.EGL_GREEN_SIZE, 0);
- int b = findConfigAttrib(egl, display, config,
- EGL10.EGL_BLUE_SIZE, 0);
- int a = findConfigAttrib(egl, display, config,
- EGL10.EGL_ALPHA_SIZE, 0);
- int distance = Math.abs(r - mRedSize)
- + Math.abs(g - mGreenSize)
- + Math.abs(b - mBlueSize)
- + Math.abs(a - mAlphaSize);
- if (distance < closestDistance) {
- closestDistance = distance;
- closestConfig = config;
- }
- }
- }
- return closestConfig;
- }
-
- private int findConfigAttrib(EGL10 egl, EGLDisplay display,
- EGLConfig config, int attribute, int defaultValue) {
-
- if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
- return mValue[0];
- }
- return defaultValue;
- }
-
- private int[] mValue;
- // Subclasses can adjust these values:
- protected int mRedSize;
- protected int mGreenSize;
- protected int mBlueSize;
- protected int mAlphaSize;
- protected int mDepthSize;
- protected int mStencilSize;
- }
-
- /**
- * This class will choose a supported surface as close to
- * RGB565 as possible, with or without a depth buffer.
- *
- */
- private static class SimpleEGLConfigChooser extends ComponentSizeChooser {
- public SimpleEGLConfigChooser(boolean withDepthBuffer) {
- super(4, 4, 4, 0, withDepthBuffer ? 16 : 0, 0);
- // Adjust target values. This way we'll accept a 4444 or
- // 555 buffer if there's no 565 buffer available.
- mRedSize = 5;
- mGreenSize = 6;
- mBlueSize = 5;
- }
- }
-
- /**
- * An EGL helper class.
- */
-
- private class EglHelper {
- public EglHelper() {
-
- }
-
- /**
- * Initialize EGL for a given configuration spec.
- * @param configSpec
- */
- public void start(){
- /*
- * 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);
- mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
-
- /*
- * Create an OpenGL ES context. This must be done only once, an
- * OpenGL context is a somewhat heavy object.
- */
- mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
- if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
- throw new RuntimeException("createContext failed");
- }
-
- 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 && mEglSurface != EGL10.EGL_NO_SURFACE) {
-
- /*
- * 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);
- mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
- }
-
- /*
- * Create an EGL surface we can render into.
- */
- mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
- mEglDisplay, mEglConfig, holder);
-
- if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
- throwEglException("createWindowSurface");
- }
-
- /*
- * Before we can issue GL commands, we need to make sure
- * the context is current and bound to a surface.
- */
- if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
- throwEglException("eglMakeCurrent");
- }
-
- 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 destroySurface() {
- if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
- mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
- EGL10.EGL_NO_SURFACE,
- EGL10.EGL_NO_CONTEXT);
- mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
- mEglSurface = null;
- }
- }
-
- public void finish() {
- if (mEglContext != null) {
- mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
- mEglContext = null;
- }
- if (mEglDisplay != null) {
- mEgl.eglTerminate(mEglDisplay);
- mEglDisplay = null;
- }
- }
-
- private void throwEglException(String function) {
- throw new RuntimeException(function + " failed: " + mEgl.eglGetError());
- }
-
- 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.
- *
- * All potentially blocking synchronization is done through the
- * sGLThreadManager object. This avoids multiple-lock ordering issues.
- *
- */
- class GLThread extends Thread implements SwapBuffersCallback {
- GLThread(Renderer renderer) {
- super();
- mWidth = 0;
- mHeight = 0;
- mRequestRender = true;
- mRenderMode = RENDERMODE_CONTINUOUSLY;
- mRenderer = renderer;
- mRenderer.setSwapBuffersCallback(this);
- }
-
- @Override
- public void run() {
- setName("GLThread " + getId());
- if (LOG_THREADS) {
- Log.i("GLThread", "starting tid=" + getId());
- }
-
- mEglHelper = new EglHelper();
- SwapBuffers();
- SwapBuffers();
-
- mRenderer.onDrawFrame(mGL);
-
- synchronized (sGLThreadManager) {
- stopEglLocked();
- }
-
- sGLThreadManager.threadExiting(this);
- }
-
- /*
- * This private method should only be called inside a
- * synchronized(sGLThreadManager) block.
- */
- private void stopEglLocked() {
- if (mHaveEgl) {
- mHaveEgl = false;
- mEglHelper.destroySurface();
- mEglHelper.finish();
- sGLThreadManager.releaseEglSurfaceLocked(this);
- }
- }
-
- public boolean SwapBuffers() {
- try {
-
- boolean createEglSurface = false;
- boolean sizeChanged = false;
- int w = 0;
- int h = 0;
- Runnable event = null;
-
- synchronized (sGLThreadManager) {
- while (true) {
- if (mShouldExit) {
- return false;
- }
-
- if (! mEventQueue.isEmpty()) {
- event = mEventQueue.remove(0);
- break;
- }
-
- // Do we need to release the EGL surface?
- if (mHaveEgl && mPaused) {
- if (LOG_SURFACE) {
- Log.i("GLThread", "releasing EGL surface because paused tid=" + getId());
- }
- stopEglLocked();
- }
-
- // Have we lost the surface view surface?
- if ((! mHasSurface) && (! mWaitingForSurface)) {
- if (LOG_SURFACE) {
- Log.i("GLThread", "noticed surfaceView surface lost tid=" + getId());
- }
- if (mHaveEgl) {
- stopEglLocked();
- }
- mWaitingForSurface = true;
- sGLThreadManager.notifyAll();
- }
-
- // Have we acquired the surface view surface?
- if (mHasSurface && mWaitingForSurface) {
- if (LOG_SURFACE) {
- Log.i("GLThread", "noticed surfaceView surface acquired tid=" + getId());
- }
- mWaitingForSurface = false;
- sGLThreadManager.notifyAll();
- }
-
- // Ready to draw?
- if ((!mPaused) && mHasSurface
- && (mWidth > 0) && (mHeight > 0)
- && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) {
-
- // If we don't have an egl surface, try to acquire one.
- if ((! mHaveEgl) && sGLThreadManager.tryAcquireEglSurfaceLocked(this)) {
- mHaveEgl = true;
- mEglHelper.start();
- createEglSurface = true;
- sizeChanged = true;
- sGLThreadManager.notifyAll();
- }
-
- if (mHaveEgl) {
- if (mSizeChanged) {
- sizeChanged = true;
- w = mWidth;
- h = mHeight;
- if (DRAW_TWICE_AFTER_SIZE_CHANGED) {
- // We keep mRequestRender true so that we draw twice after the size changes.
- // (Once because of mSizeChanged, the second time because of mRequestRender.)
- // This forces the updated graphics onto the screen.
- } else {
- mRequestRender = false;
- }
- mSizeChanged = false;
- } else {
- mRequestRender = false;
- }
- sGLThreadManager.notifyAll();
- break;
- }
- }
-
- // By design, this is the only place in a GLThread thread where we wait().
- if (LOG_THREADS) {
- Log.i("GLThread", "waiting tid=" + getId());
- }
- sGLThreadManager.wait();
- }
- } // end of synchronized(sGLThreadManager)
-
- if (event != null) {
- event.run();
- event = null;
- }
-
- if (createEglSurface) {
- mGL = (GL10) mEglHelper.createSurface(getHolder());
- if (LOG_RENDERER) {
- Log.w("GLThread", "onSurfaceCreated");
- }
- mRenderer.onSurfaceCreated(mGL, mEglHelper.mEglConfig);
- createEglSurface = false;
- }
-
- if (sizeChanged) {
- if (LOG_RENDERER) {
- Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")");
- }
- mRenderer.onSurfaceChanged(mGL, w, h);
- sizeChanged = false;
- }
-
- if (LOG_RENDERER) {
- Log.w("GLThread", "onDrawFrame");
- }
- if(!mEglHelper.swap()) {
- if (LOG_SURFACE) {
- Log.i("GLThread", "egl surface lost tid=" + getId());
- return false;
- }
- }
-
- } catch (InterruptedException e) {
- return false;
- }
- return true;
- }
-
- public void setRenderMode(int renderMode) {
- if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) {
- throw new IllegalArgumentException("renderMode");
- }
- synchronized(sGLThreadManager) {
- mRenderMode = renderMode;
- sGLThreadManager.notifyAll();
- }
- }
-
- public int getRenderMode() {
- synchronized(sGLThreadManager) {
- return mRenderMode;
- }
- }
-
- public void requestRender() {
- synchronized(sGLThreadManager) {
- mRequestRender = true;
- sGLThreadManager.notifyAll();
- }
- }
-
- public void surfaceCreated() {
- synchronized(sGLThreadManager) {
- if (LOG_THREADS) {
- Log.i("GLThread", "surfaceCreated tid=" + getId());
- }
- mHasSurface = true;
- sGLThreadManager.notifyAll();
- }
- }
-
- public void surfaceDestroyed() {
- synchronized(sGLThreadManager) {
- if (LOG_THREADS) {
- Log.i("GLThread", "surfaceDestroyed tid=" + getId());
- }
- mHasSurface = false;
- sGLThreadManager.notifyAll();
- while((!mWaitingForSurface) && (!mExited)) {
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- }
- }
-
- public void onPause() {
- synchronized (sGLThreadManager) {
- mPaused = true;
- sGLThreadManager.notifyAll();
- }
- }
-
- public void onResume() {
- synchronized (sGLThreadManager) {
- mPaused = false;
- mRequestRender = true;
- sGLThreadManager.notifyAll();
- }
- }
-
- public void onWindowResize(int w, int h) {
- synchronized (sGLThreadManager) {
- mWidth = w;
- mHeight = h;
- mSizeChanged = true;
- mRequestRender = true;
- sGLThreadManager.notifyAll();
- }
- }
-
- public void requestExitAndWait() {
- // don't call this from GLThread thread or it is a guaranteed
- // deadlock!
- synchronized(sGLThreadManager) {
- mShouldExit = true;
- sGLThreadManager.notifyAll();
- while (! mExited) {
- try {
- sGLThreadManager.wait();
- } 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) {
- if (r == null) {
- throw new IllegalArgumentException("r must not be null");
- }
- synchronized(sGLThreadManager) {
- mEventQueue.add(r);
- sGLThreadManager.notifyAll();
- }
- }
-
- // Once the thread is started, all accesses to the following member
- // variables are protected by the sGLThreadManager monitor
- private boolean mShouldExit;
- private boolean mExited;
- private boolean mPaused;
- private boolean mHasSurface;
- private boolean mWaitingForSurface;
- private boolean mHaveEgl;
- private int mWidth;
- private int mHeight;
- private int mRenderMode;
- private boolean mRequestRender;
- private ArrayList
- *
- *
- * Using GLSurfaceView
- * Initializing GLSurfaceView
- * All you have to do to initialize a GLSurfaceView is call {@link #setRenderer(Renderer)}.
- * However, if desired, you can modify the default behavior of GLSurfaceView by calling one or
- * more of these methods before calling setRenderer:
- *
- *
- * Choosing an EGL Configuration
- * A given Android device may support multiple possible types of drawing surfaces.
- * The available surfaces may differ in how may channels of data are present, as
- * well as how many bits are allocated to each channel. Therefore, the first thing
- * GLSurfaceView has to do when starting to render is choose what type of surface to use.
- * Debug Behavior
- * You can optionally modify the behavior of GLSurfaceView by calling
- * one or more of the debugging methods {@link #setDebugFlags(int)},
- * and {@link #setGLWrapper}. These methods may be called before and/or after setRenderer, but
- * typically they are called before setRenderer so that they take effect immediately.
- * Setting a Renderer
- * Finally, you must call {@link #setRenderer} to register a {@link Renderer}.
- * The renderer is
- * responsible for doing the actual OpenGL rendering.
- * Rendering Mode
- * Once the renderer is set, you can control whether the renderer draws
- * continuously or on-demand by calling
- * {@link #setRenderMode}. The default is continuous rendering.
- * Activity Life-cycle
- * A GLSurfaceView must be notified when the activity is paused and resumed. GLSurfaceView clients
- * are required to call {@link #onPause()} when the activity pauses and
- * {@link #onResume()} when the activity resumes. These calls allow GLSurfaceView to
- * pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate
- * the OpenGL display.
- * Handling events
- *
- * class MyGLSurfaceView extends GLSurfaceView {
- *
- * private MyRenderer mMyRenderer;
- *
- * public void start() {
- * mMyRenderer = ...;
- * setRenderer(mMyRenderer);
- * }
- *
- * public boolean onKeyDown(int keyCode, KeyEvent event) {
- * if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
- * queueEvent(new Runnable() {
- * // This method will be called on the rendering
- * // thread:
- * public void run() {
- * mMyRenderer.handleDpadCenter();
- * }});
- * return true;
- * }
- * return super.onKeyDown(keyCode, event);
- * }
- * }
- *
- *
- */
-public class GLSurfaceView_SDL extends SurfaceView implements SurfaceHolder.Callback {
- private final static boolean LOG_THREADS = false;
- private final static boolean LOG_SURFACE = false;
- private final static boolean LOG_RENDERER = false;
- // Work-around for bug 2263168
- private final static boolean DRAW_TWICE_AFTER_SIZE_CHANGED = true;
- /**
- * The renderer only renders
- * when the surface is created, or when {@link #requestRender} is called.
- *
- * @see #getRenderMode()
- * @see #setRenderMode(int)
- */
- public final static int RENDERMODE_WHEN_DIRTY = 0;
- /**
- * The renderer is called
- * continuously to re-render the scene.
- *
- * @see #getRenderMode()
- * @see #setRenderMode(int)
- * @see #requestRender()
- */
- public final static int RENDERMODE_CONTINUOUSLY = 1;
-
- /**
- * Check glError() after every GL call and throw an exception if glError indicates
- * that an error has occurred. This can be used to help track down which OpenGL ES call
- * is causing an error.
- *
- * @see #getDebugFlags
- * @see #setDebugFlags
- */
- public final static int DEBUG_CHECK_GL_ERROR = 1;
-
- /**
- * Log GL calls to the system log at "verbose" level with tag "GLSurfaceView".
- *
- * @see #getDebugFlags
- * @see #setDebugFlags
- */
- public final static int DEBUG_LOG_GL_CALLS = 2;
-
- /**
- * Standard View constructor. In order to render something, you
- * must call {@link #setRenderer} to register a renderer.
- */
- public GLSurfaceView_SDL(Context context) {
- super(context);
- init();
- }
-
- /**
- * Standard View constructor. In order to render something, you
- * must call {@link #setRenderer} to register a renderer.
- */
- public GLSurfaceView_SDL(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);
- }
-
- /**
- * Set the glWrapper. If the glWrapper is not null, its
- * {@link GLWrapper#wrap(GL)} method is called
- * whenever a surface is created. A GLWrapper can be used to wrap
- * the GL object that's passed to the renderer. Wrapping a GL
- * object enables examining and modifying the behavior of the
- * GL calls made by the renderer.
- *
- *
- *
- *
- *
- * @param renderer the renderer to use to perform OpenGL drawing.
- */
- public void setRenderer(Renderer renderer) {
- checkRenderThreadState();
- if (mEGLConfigChooser == null) {
- mEGLConfigChooser = new SimpleEGLConfigChooser(true);
- }
- if (mEGLContextFactory == null) {
- mEGLContextFactory = new DefaultContextFactory();
- }
- if (mEGLWindowSurfaceFactory == null) {
- mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
- }
- mGLThread = new GLThread(renderer);
- mGLThread.start();
- }
-
- /**
- * Install a custom EGLContextFactory.
- *
- * class MyGLWrapper implements GLWrapper {
- * GL wrap(GL gl) {
- * return new MyGLImplementation(gl);
- * }
- * static class MyGLImplementation implements GL,GL10,GL11,... {
- * ...
- * }
- * }
- *
- * @see #setGLWrapper(GLWrapper)
- */
- public interface GLWrapper {
- /**
- * Wraps a gl interface in another gl interface.
- * @param gl a GL interface that is to be wrapped.
- * @return either the input argument or another GL object that wraps the input argument.
- */
- GL wrap(GL gl);
- }
-
- /**
- * A generic renderer interface.
- * Threading
- * The renderer will be called on a separate thread, so that rendering
- * performance is decoupled from the UI thread. Clients typically need to
- * communicate with the renderer from the UI thread, because that's where
- * input events are received. Clients can communicate using any of the
- * standard Java techniques for cross-thread communication, or they can
- * use the {@link GLSurfaceView#queueEvent(Runnable)} convenience method.
- * EGL Context Lost
- * There are situations where the EGL rendering context will be lost. This
- * typically happens when device wakes up after going to sleep. When
- * the EGL context is lost, all OpenGL resources (such as textures) that are
- * associated with that context will be automatically deleted. In order to
- * keep rendering correctly, a renderer must recreate any lost resources
- * that it still needs. The {@link #onSurfaceCreated(GL10, EGLConfig)} method
- * is a convenient place to do this.
- *
- *
- * @see #setRenderer(Renderer)
- */
- public static interface SwapBuffersCallback {
- public boolean SwapBuffers();
- }
-
- public static abstract class Renderer {
- /**
- * Called when the surface is created or recreated.
- * instanceof 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.
- */
- public abstract void onSurfaceCreated(GL10 gl, EGLConfig config);
-
- /**
- * Called when the surface changed size.
- *
- * void onSurfaceChanged(GL10 gl, int width, int height) {
- * gl.glViewport(0, 0, width, height);
- * // for a fixed camera, set the projection too
- * float ratio = (float) width / height;
- * gl.glMatrixMode(GL10.GL_PROJECTION);
- * gl.glLoadIdentity();
- * gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
- * }
- *
- * @param gl the GL interface. Use instanceof to
- * test if the interface supports GL11 or higher interfaces.
- * @param width
- * @param height
- */
- public abstract void onSurfaceChanged(GL10 gl, int width, int height);
-
- /**
- * Called to draw the current frame.
- *
- * void onDrawFrame(GL10 gl) {
- * gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
- * //... other gl calls to render the scene ...
- * }
- *
- * @param gl the GL interface. Use instanceof to
- * test if the interface supports GL11 or higher interfaces.
- */
- public abstract void onDrawFrame(GL10 gl);
-
- public boolean SwapBuffers() {
- if( mSwapBuffersCallback != null )
- return mSwapBuffersCallback.SwapBuffers();
- return false;
- }
-
- public void setSwapBuffersCallback( SwapBuffersCallback c ) {
- mSwapBuffersCallback = c;
- }
-
- private SwapBuffersCallback mSwapBuffersCallback = null;
- }
-
- /**
- * An interface for customizing the eglCreateContext and eglDestroyContext calls.
- *