jPCT-AE - a 3d engine for Android > Bugs

Maybe a bug? Blank screen after Home button pressed

(1/8) > >>

nimo:
Hi,
first of all, thank you very much for this amazing library for Android.
I noticed a strange behaviour in my 3D application, and I noticed that the same problem is present in your demo downloaded from the site, so you'll be able to verify directly.
To reproduce the problem:

1 - Open the demo application: it works fine
2 - Press the 'Home' button to return to Android home screen
3 - Open again the demo application: now I see only a blank screen  ???

In my application, this problem occurs also when pressing the 'back' button.
Same behaviour both on my HTC Desire with Froyo 2.2 and on the Android emulator.

Thank you very much for your support
Paolo

P.S.: Sorry for my bad english (I'm Italian  ;D)

EgonOlsen:
No, that's no a bug. If you press home or back or a call comes in or a thunder storm approaches, i.e. in almost every situation, either the surface or the whole activity can be paused/stopped/destroyed. Each of these actions destroys the open gl context. The demo doesn't really deal with this (as stated in its docs). It's up to you to handle this case, it's not part of the engine. However, it offers some implicit and explicit help to ease this.

Here's what i'm doing following the suggestions that raft gave me. It might not be perfect...anyway:


* create almost all of your attributes as attributes of the Activity, not of the renderer.
* set Config.glAvoidTextureCopies to false (or as an alternative call keepPixelData(true) on each texture). This will make jPCT upload the proper texture content again after a context change.
* add a static attribute to your Activity to store the Activity itself.
* once the activity has been fully created, store this into that attribute. Watch out that at least Android 2.2 likes to create and destroy the Activity one time before it actually does anything real with it, so don't do this directly in onCreate() but later or otherwise you might store an almost empty Activity.
* in the onCreate(...)-method, check this attribute. If it's not null, use reflection to copy all the context of the stored activity into the newly created one
* design the onSurfaceChanged() and onSurfaceCreated() methods in a way that they don't do unneeded or even harmful reinitialization work when creating a surfaces for the second or the third time. All i do then is to create a new framebuffer. This is mandatory, because the gl instance has changed.
* ...anything else...i'm pretty sure, i just can't remember it. jPCT-AE does some internal things to recover from a context change automatically. You'll notice this from the log when using VBOs for example.
Or another solution that i used in my benchmark application: onPause(), onStop(),...all do a System.exit()...



raft:

--- Quote from: EgonOlsen ---once the activity has been fully created, store this into that attribute. Watch out that at least Android 2.2 likes to create and destroy the Activity one time before it actually does anything real with it, so don't do this directly in onCreate() but later or otherwise you might store an almost empty Activity.
--- End quote ---
i wasnt aware of this 2.2 thing. but i suppose we can still store our Activity in onCreate() method. for example onCreate() is still a good candidate for loading textures. this way, next call to onCreate() on next instance wont reload textures.


--- Quote ---in the onCreate(...)-method, check this attribute. If it's not null, use reflection to copy all the context of the stored activity into the newly created one
--- End quote ---
is reflection really necessary here ? i copy necessary fields manually.

EgonOlsen:

--- Quote from: raft on August 24, 2010, 05:31:23 pm ---i wasnt aware of this 2.2 thing. but i suppose we can still store our Activity in onCreate() method. for example onCreate() is still a good candidate for loading textures. this way, next call to onCreate() on next instance wont reload textures.

--- End quote ---
That should work fine too. I don't know if it's common behaviour, but my 2.2. emulator does behave that way.

--- Quote ---is reflection really necessary here ? i copy necessary fields manually.

--- End quote ---
No, of course not. You can copy them manually as well. But using reflection, i don't have to care about adding new fields. And the code is really simple:


--- Code: ---       private void copy(AlienRunner src) {
try {
Logger.log("Copying data from master Activity!");
Field[] fs = src.getClass().getDeclaredFields();
for (Field f : fs) {
f.setAccessible(true);
f.set(this, f.get(src));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}

--- End code ---

smither:
What's wrong about this? I can't click the home screen and go back becuase i lose the cube.


public class Liberable extends Activity {
   private GLSurfaceView mGLView;
   private Renderer renderer = null;
   private FrameBuffer fb = null;
   private Light sun=null;
   private World world = null;
   private Object3D cube=null;
   private boolean paused = false;
   public Liberable _instance;
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      if(_instance==null)
      {
         mGLView = new GLSurfaceView(getApplication());
         mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
            public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
               // Ensure that we get a 16bit framebuffer. Otherwise, we'll fall
               // back to Pixelflinger on some device (read: Samsung I7500)
               int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE };
               EGLConfig[] configs = new EGLConfig[1];
               int[] result = new int[1];
               egl.eglChooseConfig(display, attributes, configs, 1, result);
               return configs[0];
            }
         });
         renderer = new Renderer();
         mGLView.setRenderer(renderer);
         setContentView(mGLView);
         _instance=this;
         Log.d("Liberable","0");
      }
      else
      {
         Log.d("Liberable","1");
         copy(_instance);
         renderer.reset();
      }
   }
   
   @Override
   protected void onPause() {
      _instance.paused = true;
      super.onPause();
      mGLView.onPause();
   }

   @Override
   protected void onResume() {
      if(_instance.paused)
      {
         Log.d("Liberable","2");
         copy(_instance);
         renderer.reset();
      }
      _instance.paused = false;
      super.onResume();
      mGLView.onResume();
   }

   protected void onStop() {
      renderer.stop();
      super.onStop();
   }

   private void copy(Liberable src) {
      try {
         Logger.log("Copying data from master Activity!");
         Field[] fs = src.getClass().getDeclaredFields();
         for (Field f : fs) {
            f.setAccessible(true);
            f.set(this, f.get(src));
         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }
   
   class Renderer implements GLSurfaceView.Renderer {
      private boolean resetFB=false;
      private boolean stop = false;
      int w;
      int h;
      
      public Renderer()
      {
         Config.glAvoidTextureCopies=false;
      }
      @Override
      public void onDrawFrame(GL10 gl) {
         try {
            if (!stop) {
               if (paused) {
                  Thread.sleep(500);
               } else {
                  if(resetFB)
                  {
                     fb = new FrameBuffer(gl, w, h);
                     resetFB=false;
                  }
                  fb.clear();
                  world.renderScene(fb);
                  world.draw(fb);
                  fb.display();
               }
            }
            else {
               if (fb != null) {
                  fb.dispose();
                  fb = null;
               }
            }
         } catch (Exception e) {
            Logger.log("Drawing thread terminated!", Logger.MESSAGE);
         }
      }

      @Override
      public void onSurfaceChanged(GL10 gl, int w, int h) {
         if (fb != null) {
            fb.dispose();
         }
         fb = new FrameBuffer(gl, w, h);
         Log.d("Pepe", "w:"+w+",h:"+h);
         this.h=h;
         this.w=w;
         Log.d("Liberable","Changed");
      }

      @Override
      public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//         if (fb != null) {
//            fb.dispose();
//         }
//         fb = new FrameBuffer(gl, w, h);
         Log.d("Liberable","Created");
         TextureManager.getInstance().flush();
         world = new World();
         Resources res = getResources();
         TextureManager tm = TextureManager.getInstance();
         Texture lineasT=new Texture(res.openRawResource(R.raw.blanco),true);
         tm.addTexture("white", lineasT);
         cube=Primitives.getCube(3);
         cube.setTexture("white");
         cube.build();
         world.addObject(cube);
         sun = new Light(world);
         Camera cam = world.getCamera();
         cam.moveCamera(Camera.CAMERA_MOVEOUT, 10);
         cam.lookAt(cube.getTransformedCenter());
         cam.setFOV(1.5f);
         sun.setIntensity(250, 250, 250);
         SimpleVector sv = new SimpleVector();
         sv.set(cube.getTransformedCenter());
         sv.y -= 300;
         sv.x -= 100;
         sv.z += 200;
         sun.setPosition(sv);
      }
   
      public void stop() {
         stop = true;
         if (fb != null) {
            fb.dispose();
            fb = null;
         }
      }
      public void reset()
      {
         resetFB=true;
         
      }
   }
}

Navigation

[0] Message Index

[#] Next page

Go to full version