4

I have an EAGLView which I am resizing in an animation, with the animation driven by an NSTimer that calls a draw function. As I resize the EAGLView, I need to adjust the projection for the view to maintain the aspect ratio of the contents. The draw function looks like this:

gameView.frame = newFrame;
[gameView setFramebuffer];
[self updateProjection];

/* Drawing to the EAGLView, gameView, here, then... */  

[gameView presentFramebuffer];

Run like this, though, the contents of the EAGLView appear to "stair-step" down the animation. When I record it and look at it frame by frame, it's clear that the projection is adjusted, then the view is resized a very short time later (less than one animation frame).

I suspect that the reason is that the change in the frame of gameView is being deferred, and that in the meantime the updated framebuffer is making its way to the screen. I've tried using CATransactions to get the frame update to take effect immediately, but as I kind of expected for a UIView change, that did nothing. I suppose I could modify the viewport and leave the EAGLView full-frame, but I worry that that might just leave me with synchronization issues elsewhere (say, with updates to any overlaid CALayers).

Does this seem like a reasonable assessment of the problem? How can I prevent it -- that is, how can I best ensure that the framebuffer presentation coincides with the change in the actual frame of the EAGLView (and other CA elements)?

Thanks!

mayuur
  • 4,736
  • 4
  • 30
  • 65
Jason Cooper
  • 404
  • 3
  • 11

1 Answers1

1

I encountered a similar issue with a custom EAGLView I wrote. The problem was that when changing orientation, the view got resized and the contents stretched, and only after the animation, the scene with the right proportions was displayed.

I think yours is the same problem, and I don't think you can force CoreAnimation to wait for your view to update before rendering an animation frame, because of the way it works (CA isn't aware of the drawing mechanism of the view or the layer on which operates).

But you can easily bypass the problem: open you xib file containing the view, switch to the attributes inspector on the right. Select your EAGLView (the same applies to GLKView), and under the section View there's the Mode attribute. If you're creating the view programmatically, set the contentModeproperty.

This value describes how the view contents are managed during an animation. Until the buffer is displayed, the old scene gets resized according to that mode; perhaps you can find a mode that fits the animation you need to achieve.

  • If you're worried about proportions, the center content mode may work, but the part of scene that hasn't been rendered yet will appear empty during the animation.

  • Unfortunately the redraw mode won't necessarely make your EAGLView refresh: the view is actually redrawn, but potentially with the old contents of the color buffer. It's a problem of getting the buffer filled at the right time.

  • You could try to resize and prerender a frame big enough to cover the whole animation before starting it; or you could try to render a frame to an UIImage, replace the view on the fly, animate it, the place the EAGLView back, but this may seriously affect performance.

  • The way I solved my issue was making simply the EAGLView big enough.

  • Regarding the blending of other CALayers, as far as I tried, I encountered no synchronization issue; the EAGLView updates when it can, and the other layers too. Just set the right properties to CAEAGLLayer if you're using alpha channel, and rememeber that blending the layers every time OpenGL updates your scene may be expensive in terms of performance.

Pietro Saccardi
  • 2,602
  • 34
  • 41
  • What do you mean by 'making the `EAGLView` big enough : you draw off-screen ? – Vinzzz Apr 19 '13 at 10:07
  • No, simply setting the size to 480x480 (for example), centered in the parent view, with no resizing mask. Therefore the orientation animation occurs inside the bounds of `EAGLView`, and the camera requires no update, because there's no resizing. – Pietro Saccardi Apr 20 '13 at 07:03