iosobjective-copengl-esuikitcocos2d-iphone

Cocos2d glView does not refresh when not in view


My problem involves using UIKit with Cocos2d.

The app starts as a cocos2d app using CCDirector as the rootViewController of a navigation controller. I push another view controller on top without animation by grabbing a screen shot of the glView and immediately displaying that view which is then animated onto the new view. The new view is a gallery that contains thumbnails of prior scenes.

[self.shelf animateOffScreen];
[UIView animateWithDuration:.2 animations:^{
    self.deleteButton.center = CGPointMake(kAnimateButtonOffX, self.deleteButton.center.y);
    self.infoButton.center = CGPointMake(kAnimateButtonOffX, self.infoButton.center.y);
    self.galleryButton.center = CGPointMake(kAnimateButtonOffX, self.galleryButton.center.y);
    self.cameraButton.center = CGPointMake(kAnimateButtonOffX, self.cameraButton.center.y);
} completion:^(BOOL finished) {
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    SSGalleryViewController *gallery = [storyboard instantiateViewControllerWithIdentifier:@"gallery"];
    gallery.startImage = self.scene.lastScreenGrab;
    gallery.playarea = self.scene;
    gallery.delegate = self;
    [self pushViewController:gallery animated:NO];
}];

When a user chooses a different scene to start, the thumbnail graphic of the saved scene is scaled back up to cover the entire screen.

self.playarea.sceneName = feltBoard.filename;
[[NSUserDefaults standardUserDefaults] setObject:feltBoard.filename forKey:kDataArchiveKey];
[[NSUserDefaults standardUserDefaults] synchronize];

SSScene *aScene = [[SSScene alloc] initWithDelegate:self.playarea];
[aScene restoreScene];

GMGridViewCell *cell = [self getCellForKey:feltBoard.filename];

UIImageView *endView = (UIImageView*)[cell viewWithTag:kCellImageTag];
endView.center = [self.view convertPoint:endView.center fromView:cell];
[self.view addSubview:endView];

[UIView animateWithDuration:.3 animations:^{
    endView.frame = CGRectMake(0,0, self.view.frame.size.width, self.view.frame.size.height);
} completion:^(BOOL finished) {
    if (finished) {              
        [self.delegate dismissGallery:self];
    }
}];

Then the view controller is popped so that the rootViewController (CCDirector) regains control. When this happens there is a blink where the last scene displays for an instant before the restored scene is shown.

UIView *tempView = [gallery.view viewWithTag:50];
[tempView removeFromSuperview];
[self.view insertSubview:tempView atIndex:0];
[self popViewControllerAnimated:NO];

[self.shelf animateOnScreen];

[UIView animateWithDuration:.2 animations:^{
    self.deleteButton.center = CGPointMake(kAnimateButtonOnX, self.deleteButton.center.y);
    self.infoButton.center = CGPointMake(kAnimateButtonOnX, self.infoButton.center.y);
    self.galleryButton.center = CGPointMake(kAnimateButtonOnX, self.galleryButton.center.y);
    self.cameraButton.center = CGPointMake(kAnimateButtonOnX, self.cameraButton.center.y);
} completion:^(BOOL finished) {
    if (finished) {
        [tempView removeFromSuperview];
    }
}];

I have tried to update the one scene by removing nodes and adding new nodes (so that there is really only one scene being used) and I get the flash.

I have tried creating a new scene and replacing the running scene with it, but I still see the flash.

I believe I am seeing what was left in the openGL buffer when I left the scene. But, glFlush() has no effect.

I think I need a way for the glView to be refreshed and show the changes I have made to it when it was covered by the gallery UIView.

Any ideas on what might be happening or how I might be able to correct this problem?


Solution

  • You can force the CCDirector to draw contents to the frame buffer. Run this just after you setup the new scene.

    Depending on the cocos2d version you can do:

    [[CCDirector sharedDirector] visit];
    

    or

    [[CCDirector sharedDirector] drawScene];
    

    to force updating the framebuffer immediately. Otherwise cocos2d will draw on the next display link refresh event which may not occur until the next frame, and may be deferred even longer because all the time-consuming setup code happens in the first frame.