I am having a bizarre problem where if the View that contains my GLSurfaceView is not the first to be shown by my ScreenController, then the GL commands never actually get drawn. If the GLSurfaceView is drawn first, then everything renders perfectly. Does anyone have any ideas why this is happening? Below are the two files:
---------------------------------------------------- ScreenController.as ---------------------------------------------------- public class ScreenController extends ViewAnimator { public static final String SCREEN_ID = "mCurrentScreenId"; public class ScreenAnimationListener implements AnimationListener { private int nextScreenId = -1; public void onAnimationEnd(Animation animation) { ScreenController gc = ((DecadesActivity) getContext()) .getController(); if (animation == mOutAnimation) { gc.removeScreen(); if (nextScreenId != -1) { gc.getHandler().showScreen(nextScreenId); } } else if (animation == mInAnimation) { } } public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub } public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub } public void setNextScreen(int id) { nextScreenId = id; } } /** * A handler for sending messages to the controller on its own thread. Used * for screen changes only. */ public class UIThreadHandler extends Handler { public void handleMessage(Message msg) { if (msg.what != -1) { ScreenController.this.showScreen(msg.what); } } public void restoreState() { this.removeMessages(-1); sendMessage(obtainMessage(-1)); } public void showScreen(int id) { this.removeMessages(id); sendMessage(obtainMessage(id, 0)); } } // These are all the possible game states. Every screen in the game will set // one of these // after it is activated. ScreenAnimationListener animListener = null; UIThreadHandler handler = new UIThreadHandler(); private Bundle mAltBundle = null; ViewGroup mCurrentScreen = null; // ! A reference to the currently displayed private int mCurrentScreenId = -1; Animation mInAnimation = null; // ! The animation used for a view coming in. Animation mOutAnimation = null; // ! The animation used for an exiting view. int mLevelIndex = 0; // ! The array index of the current level. boolean mPaused = false; boolean mRestoring = false; // ! A flag used to determine if a view is being public ScreenController(Context context, AttributeSet attrs) { super(context, attrs); } public Bundle getAltBundle() { return mAltBundle; } @Override public UIThreadHandler getHandler() { return handler; } public int getScreenId() { return mCurrentScreenId; } public void restoreScreenState(Bundle bundle) { mCurrentScreenId = bundle.getInt(SCREEN_ID); showScreen(mCurrentScreenId); if ( mCurrentScreen != null ) { ((ScreenLayout)mCurrentScreen.getChildAt(0)).restoreState (bundle); } } public Bundle saveScreenState() { Bundle map = new Bundle(); map.putInt(SCREEN_ID, mCurrentScreenId); // Save level scores. if ( mCurrentScreen != null ) { ((ScreenLayout)mCurrentScreen.getChildAt(0)).saveState(map); } return map; } /** Initializes our game controller **/ public void init(boolean start) { GameTimer.getTimer().start(start); animListener = new ScreenAnimationListener(); mInAnimation = getInAnimation(); mOutAnimation = getOutAnimation(); mOutAnimation.setAnimationListener(animListener); mInAnimation.setAnimationListener(animListener); if (start) showScreen(R.layout.title_screen); } public ScreenLayout getActiveScreen() { return (ScreenLayout)mCurrentScreen.getChildAt(0); } /** * Clears out a screen. Usually called after the out animation has completed **/ public void removeScreen() { if (mCurrentScreen != null) { mCurrentScreen.removeAllViews(); mCurrentScreen = null; } } /** * Screen swap function. Calling this will swap out the current screen with * the specified one. **/ public void showScreen(int screenId) { // First, find the view requested. if (mCurrentScreen != null) { animListener.setNextScreen(screenId); mCurrentScreen.startAnimation(mOutAnimation); } else { postInvalidate(); mCurrentScreenId = screenId; ViewGroup v1 = (ViewGroup) findViewById(R.id.rootPane); mCurrentScreen = (ViewGroup) View.inflate(getContext(), mCurrentScreenId, v1); mCurrentScreen.startAnimation(mInAnimation); } } } --------------------------------------- GLView.as --------------------------------------- public class GLView extends SurfaceView implements SurfaceHolder.Callback { /** * An EGL helper class. */ private class EglHelper { EGL10 mEgl; EGLConfig mEglConfig; EGLContext mEglContext; EGLDisplay mEglDisplay; EGLSurface mEglSurface; public EglHelper() { } /* * Create and return an OpenGL surface */ public GL createSurface(SurfaceHolder holder) { /* * The window size has changed, so we need to create a new surface. */ if (mEglSurface != null) { /* * Unbind and destroy the old EGL surface, if there is one. */ mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); mEgl.eglDestroySurface(mEglDisplay, mEglSurface); } /* * Create an EGL surface we can render into. */ mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, holder, null); /* * Before we can issue GL commands, we need to make sure the context * is current and bound to a surface. */ mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); GL gl = mEglContext.getGL(); if (mGLWrapper != null) { gl = mGLWrapper.wrap(gl); } return gl; } 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; } } /** * 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; } /** * 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; } } /** * A generic GL Thread. Takes care of initializing EGL and GL. Delegates to * a Renderer instance to do the actual drawing. * */ class GLThread extends Thread { private boolean mContextLost; private boolean mDone; private EglHelper mEglHelper; private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>(); private int mFrameRate; private boolean mHasFocus; private boolean mHasSurface; private int mHeight; private boolean mPaused; private Renderer3D mRenderer; private int mWidth; GLThread(Renderer3D renderer, String threadName) { super(); mDone = false; mWidth = 0; mHeight = 0; mRenderer = renderer; mFrameRate = renderer.getFrameRate(); setName(threadName); } private Runnable getEvent() { synchronized (this) { if (mEventQueue.size() > 0) { return mEventQueue.remove(0); } } return null; } 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; int delta = -1; if (mFrameRate > 0) { delta = 1000 / mFrameRate; } long time = System.currentTimeMillis(); /* * 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; } if (needToWait()) { while (needToWait()) { wait(); } } if (mDone) { break; } changed = mSizeChanged; w = mWidth; h = mHeight; mSizeChanged = false; } if (needStart) { mEglHelper.start(configSpec); tellRendererSurfaceCreated = true; changed = true; } if (changed) { gl = (GL10) mEglHelper.createSurface(mHolder); tellRendererSurfaceChanged = true; } if (tellRendererSurfaceCreated) { mRenderer.surfaceCreated(gl); tellRendererSurfaceCreated = false; } if (tellRendererSurfaceChanged) { mRenderer.sizeChanged(gl, w, h); tellRendererSurfaceChanged = false; } if ((w > 0) && (h > 0)) { /* sync frame rate */ if (System.currentTimeMillis() - time < delta) { try { Thread.sleep(System.currentTimeMillis() - time); } catch (InterruptedException ex) { } } /* draw a frame here */ mRenderer.drawFrame(gl); time = System.currentTimeMillis(); /* * 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() { return (mPaused || (!mHasFocus) || (!mHasSurface) || mContextLost) && (!mDone); } public void onPause() { synchronized (this) { mPaused = true; } } public void onResume() { synchronized (this) { mPaused = false; notify(); } } public void onWindowFocusChanged(boolean hasFocus) { synchronized (this) { mHasFocus = hasFocus; if (mHasFocus == true) { notify(); } } } public void onWindowResize(int w, int h) { synchronized (this) { mWidth = w; mHeight = h; mSizeChanged = true; } } /** * 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); } } 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(); } } @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(); } } public void surfaceCreated() { synchronized (this) { mHasSurface = true; mContextLost = false; notify(); } } public void surfaceDestroyed() { synchronized (this) { mHasSurface = false; notify(); } } } public interface GLWrapper { GL wrap(GL gl); } /** * A generic renderer interface. */ public interface Renderer3D { String name(); /** * Draw the current frame. * * @param gl */ void drawFrame(GL10 gl); /** * @return the EGL configuration specification desired by the renderer. */ int[] getConfigSpec(); int getFrameRate(); void setFrameRate(int fr); /** * Surface changed size. Called after the surface is created and * whenever the OpenGL ES surface size changes. Set your viewport here. * * @param gl * @param width * @param height */ void sizeChanged(GL10 gl, int width, int height); /** * Surface created. Called when the surface is created. Called when the * application starts, and whenever the GPU is reinitialized. This will * typically happen when the device awakes after going to sleep. Set * your textures here. */ void surfaceCreated(GL10 gl); } private static final Semaphore sEglSemaphore = new Semaphore(1); private GLThread mGLThread; private GLWrapper mGLWrapper; private SurfaceHolder mHolder; private boolean mSizeChanged = true; public GLView(Context context) { super(context); init(); } public GLView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed mHolder = getHolder(); mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mGLThread.requestExitAndWait(); } /** * Inform the view that the activity is paused. */ public void onPause() { mGLThread.onPause(); } /** * Inform the view that the activity is resumed. */ public void onResume() { mGLThread.onResume(); } /** * Inform the view that the window focus has changed. */ @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); mGLThread.onWindowFocusChanged(hasFocus); } /** * 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); } public void setGLWrapper(GLWrapper glWrapper) { mGLWrapper = glWrapper; } public void setRenderer(Renderer3D renderer) { mGLThread = new GLThread(renderer, renderer.name()); mGLThread.start(); } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // Surface size or format has changed. This should not happen in this // example. mGLThread.onWindowResize(w, h); } public void surfaceCreated(SurfaceHolder holder) { mGLThread.surfaceCreated(); } public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return mGLThread.surfaceDestroyed(); } } --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Android Developers" group. To post to this group, send email to android-developers@googlegroups.com To unsubscribe from this group, send email to android-developers-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/android-developers?hl=en -~----------~----~----~----~------~----~------~--~---