Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2007-211
$eventId
ID of event: wwdc2007
$eventContentId
ID of session without event part: 211
$eventShortId
Shortened ID of event: wwdc07
$year
Year of session: 2007
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2007] [Session 211] Adding Core...

WWDC07 • Session 211

Adding Core Animation to Your Application

Leopard Innovations • 58:33

Core Animation is an incredible layer-based animation system that will revolutionize the user experience of your application. Come learn how the automatic animation capabilities of Core Animation make compositing and animating 2D, 3D, and video content easy. See how to use this capability to explore new forms of data visualization and user interaction. Don't miss this opportunity to learn how Core Animation will transform your application.

Speakers: Haroon Sheikh, John Harper

Unlisted on Apple Developer site

Downloads from Apple

SD Video (189 MB)

Transcript

This transcript has potential transcription errors. We are working on an improved version.

I'm Haroon Sheikh. I manage the Core Animation of the Quartz team, and we've got a great session for you today. We're going to be talking about a great new Leopard innovation called Core Animation and see how you can actually get that into your application. So many of you were already in the session before this so this is going to be follow up on most of that same content, and for those who are new we'll build up on some core fundamentals, you know, like introduce Core Animation, the layers themselves, talk about the animation model, and then the bulk of the session will actually go over the Core Animation APIs, and we'll have a few demos through the session itself.

So it should come as no surprise that over the last several years we've got this evolution going on in terms of the user interface itself. More and more applications are requiring seamless compositing. You've got animations and transitions going on. A lot of the content is actually quite dynamic in nature and the UI is actually providing a much richer user experience.

So I just wanted to talk about an example from Tiger. We're got the iChat U+3 as part of iChat AV and you've got QuickTime sources coming from multiple sources and all of that is just animating over time really seamlessly with great frame rate. iTunes Coverflow, you've all seen that, everyone is used to it and it's a great way of visualizing your data through your artwork, album art.

Finally you've got full-screen applications like Front Row and consequently Apple TV itself where you've got great content coming through from the web, from your main machine, and just being presented in a nice and great way in terms of layers sort of moving across the screen and with the right quality of animation as opposed to too much animation in your face.

So I'll have a lot more examples of this stuff in Leopard. You've already seen some of these at the demo, in previous demos, and in the keynote itself, but what you really should recognize is that you really want to be part of this wave of applications that are moving into this new era, and the way to do that is really, you want to rethink the way your applications work and portray your data and sort of reexamine how you can portray your data with some hints of animation so the presentation is actually really nicely done.

So, and part of the reason is you really don't want to be left behind as your competitors, or just as the rest of the OS sort of moves in this direction. Trying to get some of this content done is relatively not hard I would say, but it's just that in the past you'd have to go down into the OpenGL level.

Most of the examples I showed you already, basically they had to go through to a step of making sure that they could take advantage of OpenGL efficiently, uploading textures at the right frame rate, at the right time to get that seamless animation through the system and that's where we actually decided, let's bring all of the fundamental things in terms of Core Animation that those animation applications provided, and let's bring that into the OS and provide that as a service to you so that you can do some of those same things.

So Core Animation, you've heard about it already, but the key thing is it's actually a foundation for both compositing and animation. So you could even actually use Core Animation for the sole purpose of just layer compositing, and that's a great functionality in itself, and on top of that, you can actually animate that content. So it is part of the QuartzCore framework and very similar to what you heard already in terms of all of these layers that you briefly were mentioned in the previous session are very analogous to NSViews .

The content of these layers can come from lots of different sources. We talked about those already in the previous session, but it could be Quartz content, it could be OpenGL content, even Core Text all sort of coming into the picture. You can apply a bunch of layer effects to that, shadow effects, masking effects, to get really rich content.

You've got these layers and now the key thing about Core Animation is it is a declarative animation engine. As a result, you don't have to sit there and program every frame of your application. The examples I showed you, they effectively have to do that. They have to go through and actually position all of those layers or their concept of layers and objects and textures at the right location at the right time, whereas Core Animation actually abstracts a lot of that for you, and actually, you can use it without having to worry about much of the details.

So in terms of the architecture, Core Animation is at the center, but the key thing is it's sitting on top of OpenGL. So to answer the question that was there at the previous session, Core Animation sits on top of OpenGL but it actually can use all of the Leopard-supported graphics cards. So it's actually not restricted to the programmable GPUs or anything else like that, and that's a key reason why you might actually want to use Core Animation itself.

In the past, you may have had to go down to OpenGL trying to get it all done right and correctly with the right texture formats, uploading it at the right time, looking at all the hints and tricks that you need to do there. Now you can actually use Core Animation itself, and it will worry about all of those details. So, like I mentioned earlier, if you just use it for the compositing part of it, I mean that's a great step forward, and it will just work across the graphics cards supported by Leopard.

We're got all of the other Quartz and media technologies such as QuickTime also being utilized as part of Core Animation itself, and then fundamentally you can actually also use it at the Cocoa level. So our goal was to actually get high quality and high performing animation, so you want to be able to hit that 60 frames a second frame rate.

We do that by actually making sure that your application does not have to redraw often. Ideally, you are not actually drawing every frame, so much of your content is actually, you can draw it once. Core Animation will actually buffer that content up for you, reuse it again and again unless you specify that you need to change that content.

When you're resizing, when you've got relayout going on, you're moving things around, for the most part things are not necessarily changing in terms of the content. I mean they may be animating in terms of movement or repositioning themselves but the content itself is not necessarily changing. So ideally, in that case, Core Animation doesn't necessarily have to call back to you.

If you've got text views or anything else like that, yes, they do need to reflow appropriately. But here is another way where we can avoid calling back into the application code itself, and we can actually eliminate some of the code that actually requires you to run at the frame rate and that sort of gives us that performance boost.

And you've heard in many sessions previously that Core Animation is taking advantage of multicore functionality through multithreading, and it actually runs a complete rendering on a separate thread for you. We talked about layers briefly, but what are they? And I'll just go through an example, a very simple one. But you've got a photo in one layer, another text layer on top of that followed by a graphic overlay, which is yet another image maybe, and as far as what the user sees it's just this is your composited result that gets presented.

These layers can have content coming from multiple sources. We've talked about CoreText. OpenGL content, you can actually draw through a GL context itself. QuartzComposer compositions can be placed as past of these layers. You can actually capture movies from QuickTime and also at the same time playback movies. Quartz 2D images in terms of being able to set a layer's content to come from an image source is actually quite useful, and actually quite used in the system. Also, you can actually draw your own content through Quartz 2D itself. Another point about layers themselves are that they are quite lightweight in nature.

So you've seen some of the demos and examples, and last year we had a demo that showed 6,000 layers sort of animating. I'll have a video of that for those who haven't seen that. But they key is these are very lightweight data structures and our goal was to make sure that you can actually have thousands of these in the system.

Layers can have transforms on them, and we do that basically by allowing a perspective transform, which is a four-by-four matrix. As a result, you can actually get, depth sorting is handled automatically for you. One thing we do not support necessarily is the ability to have layers intersect, and so that is an area that is not defined. But that doesn't stop us from doing great animation like this stuff, this particular one from last year.

So I'll let that go for a little bit, but you've got lots of layers present there, all animating over time. You've got, a lot of this animation is done through this concept of hierarchy, a layer tree that you sort of modify the root or the parents and everything sort of follows from that.

So this layer tree, you've got these layers, you want to define them into a tree. And it is a very simple concept where every layer can have a sublayer. As a result of that, you can actually construct a tree. It is a back-to-front composition model in the sense that the next thing you add will get recomposed on top of what was there previously.

These layers can have Core Image filters applied to them, onto their content itself and also into the background. So the example on the bottom right sort of shows a blur effect being applied to only a portion to the background, but sort of restricted by the layer's mask to define the area effect.

You've got layers now in a layer tree, now you want to actually animate them. So there are a lot of layer properties that you can animate. We'll talk about all of those properties a little later in the session. These animations are configurable in terms of what the timing features from a particular point to another point specifying the duration. You can also customize all of that, apply a keyframe to it, apply it along a path, transitions on them, animation groups. So a lot of this was actually discussed in the previous session.

The other thing you might want to do with this layer tree is, the layer tree is animating but you may want to find out what's the current value of a particular property and so we provide a way to query the animation status, and it's really useful for hit testing purposes.

One key thing to remember about the animation itself is by default when you change a property you are triggering an implicit animation, and let me talk about that a little more. So here, I've got a simple example of the Core Animation icon and the layer effectively, and all I really want to do is set the opacity value to zero. Your code executes and effectively what that means is as far as you're concerned the opacity value is zero, but it's actually occurring over a default time period so that it will actually fade out over its default value.

Similarly, we're got this concept of transactions. You want to make sure that all of these operations are being done. In Atomic updates, I've got a few more layers here, and what if I wanted to set the blue layer's opacity to zero, the size to zero, and the green layers x value to 500? And all of that is also done simultaneously in an Atomic update. So you don't actually see partial frames showing up.

So let me just quickly go through some of the examples in Leopard itself. So I list a few here, and I'll go through a few of them with more screenshots and with more detail. One thing to remember is the Dock on Leopard is actually a full-blown Core Animation application. So it's actually doing all of its effects through Core Animation. So it gives you a sense about the power of Core Animation right there. We've got things like the icons and the reflections in the Dock itself of the icons.

Then you've got the stacks feature, which is really great. I mean, you sort of specify the animation that you've seen associated with it, it sort of flows out. It's very easy to do with Core Animation itself. Start value, end value and let Core Animation handle it animating across a path for you. You've seen Time Machine a few times already at WWDC already, and here you've got all of these windows, Finder windows, they are actually Core Animation layers themselves.

Preview is yet another great example of this. Preview takes advantage of another feature of Core Animation called tile layers, which is newer than last year's WWDC. And what that really allows you to do is handle large image data set, and so you'll get called back to handle each one of these subtiles as needed. But it allows you to handle larger than 2K-by-2K image files across all of the GPUs that we support. Preview also has a great slide show for you to take advantage of in Core Animation.

Finders Quick Look is also taking advantage of Core Animation. You've seen demos of this. I won't go into this in too much detail. But Xray, here's another example. Xrays got a colorful view itself also. You have several runs and you want to sort of visualize them and sort of see all of them present at the same time.

Here is a great way of actually taking advantage of Core Animation. So let me actually go over and talk to you and show you a demo of two things. One of them is already available to you in your seed, which is ConvertFlow, which is nothing more than a simple way of doing Power Flow in your application.

So you've got access to this already. I recommend you play with it to get an idea of how Core Animation is done directly at the Core Animation level as opposed to the AppKit level. It's doing nothing more than basically taking all of your desktop images and you can sort of, as you expect you could sort of cycle to these seamlessly and with high frame rate.

As an exercise I'd recommend maybe what you should do is sort of play with it, and try changing it so maybe the center one is a larger size, or sort of applying animation to the entire group of these layers. So maybe do something else with it. Maybe it could bounce up and down, whatever you want to try. But that's left as an exercise for you guys to do.

The other demo I wanted to show you is Core Animation TV. So I want to thank actually the BBC motion gallery for most of this content. So the goal here is you're watching TV, and so you've got a heads up display that allows you to sort of go through different channels and at the same time different shows on this channel. So it shows you the power of Core Animation right there. And as you notice, we can do things like have all of these movies coming in with different transitions.

At the same time, we could also bring in the channel list and select any channel you want. We've got 4 or 5 or so channels right here. Let me go into the selection of, the shows associated with that channel and then we can sort of choose that. So the goal we wanted to show you here was just QuickTime content being played in the background, and then with different content on top of it. A lot of this is actually implemented through Core Animations Scroll Layer feature, which allows us to sort of scroll around in this larger space and have all of these layers sort of show up appropriately.

So we've got QuartzComposer composition running in the background here. At the same time, we can also start putting in new content. So here, we've got a layer, a series of layers. I mean, the actual layer itself is actually that thing there but we actually put other layers on top of that to sort of help out with some of these other controls. For example, you'll also notice that in here I've got Core Image filters being applied to some of these buttons. So there is a bloom effect sort of being applied there.

And in this case, the clock is actually done as a Quartz2D content. Every second it's actually drawing the clock hands appropriately. There is other things that you can put in here and after this session I hope, the stock prices go up to that value. Other things here, and then you could also do GL content in here. So let's say I wanted to have that stick around.

I'm back here, and so it shows a great way of how some of these different technologies can be sort of incorporated together into your applications. So, let me go back to slides. And at this point, I'd like to invite John Harper to actually go over some of the details associated with Core Animation itself.

Thanks, Haroon. Okay, how does this work? Okay, so the first thing to bear in mind about Core Animation is that it's a little different from some of the APIs we have in that it's very much data driven.

And what that kind of means is that most of time you're not really thinking about the functions of the call or imperative type programming, but really how to try to control and define the description of what you want to see. So we talked about layers of animations, and so this basically means that the layers are just kind of a property-based object with a bunch of properties and a bunch of sublayers and all this kind of stuff, and the way you drive the framework is just to set the properties and configure the objects and let the engine take up all the strain and do the work in the background.

And so we take of a lot of advantage from the new Objective-C features, so all of the API is defined in terms of Objective-C properties. This gives you some nice things in terms of subclassing, but mainly you get the nice dots and tags which we all love. And then because it's a data model, we have to kind of define how this, what this means in terms of getting the changes to the screen, and the way we do that is that we define these things called transactions.

And a transaction, all you really need to know to start with is that the transaction includes all your changes from each iteration around the event loop. So you can change whatever you'd like. At the end of the event loop, we collect all these things up and push them to the screen in a single update.

So let's go through, in a little more detail now, how each layer is constituted. So first of all, each layer has some geometry. So they have a rectangle, which defines their own kind of coordinate space, the bounds. They have a position in the containing space and some other properties, like they have, you can have a curved corner or a chance of putting them into a 3D space and a few other things, which we'll leave in the header files.

Once you fill out the geometry then we look at the kind of the forming things that make up the image of the layer, and the first thing which is drawn on the bottom of the stack is the background color. And obviously, the background color sits in the space, the corner space there and follows around the corners and that kind of thing.

On top of the background, we put the content, and this is the stuff you draw or the image you give us, and there are a number of ways to kind of plan how that content is mapped into the layer, the layer geometry. Because, for example, the image may be bigger or smaller than the layer itself, so you can tell us align to the top left or the bottom right or resize or whatever. The content's rect we'll get to later.

So then, on top of the contents and the background you get the sublayers; traditional, kind of recursive sublayer, subview compositing model. The one slightly different thing here is that the sublayers can actually extend outside their parent. You can tell them to clip or not clip. We'll get to that later as well.

Once you've got the sublayers we come to the border, and the border is not often used but sometimes it's useful, and it just gives you a ring around the edge of the layer and you can define the color and the width and that's about it. So now, we have this thing. We have the background color, the contents, the sublayers, and the border, and this gives us the basic image of the layer.

So the next set of properties kind of tell us what to do with that, and the first thing which we talked about already is you can apply Core Image filters. So you can give us an array of filters which are applied in order to just kind of take the original image and push it through each filter in turn and give us some output. In this case, we're using a morphology filter. You can also have a shadow, which has the standard kind of configuration.

In this case it's red for some reason. And once you've got that, the last final thing you often want to set is the opacity. So now we finished with that and we got kind of the image in isolation, and then the next thing we do in the rendering model is we composite it into the background, which is kind of everything which was drawn up to this point. And you can use a filter for that, like a blend, blur, or something.

And then finally once you've got this kind of composited image of the layer into the backdrop, we then can use a mask to kind of reclip it or apply it into the original destination. So in this case we used an Apple mask for some reason. I mean these are all things that you can read about later in the documentation.

So we talked a bit about mixing content, and the way we do that largely is by defining a bunch of different subclasses. The CALayer is great for doing the standard kind of image-based, CGContext-based drawing. But if you want larger data, which actually is bigger than the graphics card can support, then you typically have to use the TiledLayer, where if you want OpenGL data you have to use the OpenGLLayer, and so on.

Oh, I should say that the ScrollLayer is just some convenient things for scrolling. Okay, so like any other object, the way you deal with these things is you allocate them. First, obviously, give you a pointer, and then you typically set a bunch of properties on the layer. So you can, for example, set the background color of your layer to white and then set its size to 100-by-100 or whatever. And then once you've configured it, the next thing you normally do is add it to an existing superlayer to put it into this kind of recursive compositing tree.

Once it's in the layer tree, assuming its parent of the top of the tree is visible, then at some point we get this kind of transactional-based layout of the drawing model, which we'll talk about in the next slides. So once you've gone through this stage and it has been committed at the end of the event loop, it's on the screen. It's been drawn and you no longer have to really care about it unless you want to change the properties, and of course, finally you may end up removing it, deallocating the layer. So we can go through that in a little more detail.

So the first line is we're going to create that layer. We just use the standard kind of initializer, allocater type convenience method. Then in this case we're just going to say give it a fixed point on screen in its parent's corner space, like a little box in the corner in this example.

And then we're not going to do any custom drawing. We're just going to say here's an image which we presumably loaded off disk or drew earlier, and say this is your contents for the layer. And in this case, because we haven't told it to do anything else it will resize to fit the bounds of the layer.

And then, as I said earlier, we have to add it to the layer tree so we use this convenience method to modify the sublayer's property of my superlayer. And once we've done that and my superlayer is already visible, then we'll get some kind of default cross-fade transition, and it will just appear on the screen.

Okay, so back to layout and drawing. Two of the main things you want to do with layers once you've created them is position them and then draw into them. So we kind of wrap that up in a way that makes it a little more convenient, and it's very similar to the NSView drawing model in that we give you a way to kind of defer all these actions until immediately before we commit them onto the screen. So layout is the first pass, and this basically gives you a chance to hook in and kind of position all your sublayers somewhere in the global space. And so there is two ways really of defining layout behavior.

You can subclass the layer, which we will show later, or you can assign a delegate. In both cases, you typically call this -setNeedsLayout method just to say I need layout, and then in the subclassing case you would implement the -layoutSublayers method, or in the delegate case, you would implement some other kind of third-party object which implements basically the same method.

And that gets called when you set that as the layout manager property of the layout. Delegates or layout managers are pretty useful in that you can kind of encapsulate reusable layout algorithms, I guess. So for example, if you know that a bunch of your different subclasses all need a grid layout method or a box one depacking or whatever, then you can wrap that up in a layout manager and just you know, reuse that for every layer.

We give you one existing layout manager which is called the ConstraintLayoutManager, and this is a nice way to kind of describe kind of spatial layout constraints. So you could say that if I have 5 sublayers, then the first one, his left edge is relative to the right edge of the next one and things like this. Finally, if you really want to use the old style stuff, we also have the autoresizing mask property from NSView and that works just like in NSView.

So drawing is pretty similar to layout, and it runs, but in this case, you're not positioning things on screen. You're actually drawing into the layers. I should say here that you don't have to draw into the layers. Like we saw earlier, you could just set the contents of the layer to be some image, and that works in a lot of cases, but also often, you want to do custom CG drawing.

And so the best way to do that is just call -setNeedsDisplay on the layer, and then implement the drawing context method. And if you do that we can create a buffer for you in the optimal format for the graphics card, the optimal size, set it all up correctly, reuse the CG context, and then just give it to you to draw into.

So the point of the bottom is very important, you should never call -setNeedsDisplay unless you're sure you do need to display, because if you do, we've seen this in some cases, you'll end up with a, kind of, layer size transparent image just sitting in the stack taking fill rate for no reason.

Okay, so now we're going to go through subclassing in a little more detail. One of the main reasons of the subclass is you want to add properties to layers. So, in this case, if we're imaging that we have some kind of customs drawing code, but we want to reuse the layer, so we're going to add a lineWidth property, and presumably we're going to use this when we actually draw into the layer, to kind of use some special behavior. So the first thing we'll do is in our header file we will declare this lineWidth property, and we do it in the normal Objective-C 2.0 @property syntax.

But the thing to, kind of, be aware of is that for the most optimal behavior you really want to let Core Animation implement all the properties. So you don't want to do @synthesize or define your own set of getter methods unless you have a real good reason to.

The best thing is just say, @dynamic in the implementation file, which just tells the compiler I'm not going to do anything here, and then at runtime Core Animation can introspect all the classes and see, well, this guy didn't implement this property, so I'm going to do it for him.

And that basically means we'll create the setter/getter methods and all that kind of stuff, and manage the properties for you. So the first thing, after declaring the property, is typically you want to give it a default value. If the default value is zero you don't have to do anything, we'll do that for you, but if it's not zero, the thing to do is override this default value for key method and then you can check the key, and if it's your property, then it just returns on value. This doesn't have to be particularly efficient because we cached the values when we first used the class.

So once you've given it the default values, the next thing to be aware of is, typically most times you @properties you're doing it because you want to change the layout or drawing behavior, so that means if a property changes, it's kind of convenient if the layout or drawing kind of updates itself automatically. So the way we found it's best to do that right now is, you can override this KVO method to changeValueForKey.

And, obviously, all property changes will go through this method, and then the same way for the default value, you can just kind of check your key and then do something. In this case, we are going to say, if the key is lineWidth we know we have to redraw the layer so we are just going to say -setNeedsDisplay.

Finally here, since we're going to do some drawing, we're going to override the drawing context method and here we're going to use the @property value. You can use your imagination what we're going to draw, because I was running out of space. But, basically, you just say self.property, and everything kind of works.

And that's basically how to subclass. So, a little kind of sidestep, the CALayers is great for, you know, normal-sized data, and normal is kind of about up to 2000 pixels by 2000 pixels, but if you want more, if you want larger data or the data that has, potentially, multiple levels of resolution, where that means, you know, you may have a representation or can generate one at 50 percent or 25 percent, and so on, then you'd probably want to use the TiledLayer.

The TiledLayer is a really nice way to kind of manage all this stuff asynchronously, and it doesn't ask you ahead of time for the data, it just kind of waits and sees what's being rendered on the screen, and it will ask you, kind of asynchronously, give me the tiles for region 0,0 or 100, 100. And the other thing is, it also manages the level of detail.

So it sees that you're zoomed right out on this kind of 10,000-by-10,000 pixel layer, then it will probably ask you for a level of detail that kind of ten percent size or something, and that means that it can really minimize the amount of bandwidth it's using to, kind of, put that thing on the screen.

Also, of course, it lets you do whatever kind of filtering you want, so you probably end up with a better result. So, I guess the last point is that we said earlier you can always assign to the contents property, and that's not true here. If you do that, you basically make it a non-TiledLayer.

Okay, so back to animation. I guess the previous session talked a bit about this, but basically, we have the CAAnimation Class to represent all of animations. And the way the animation model works is that just like the layer model where you describe what you want to see on the screen, you do the same thing with animation.

You create the object, you set all the properties to describe, you know, the animation you want to see, and then you just add it to the layer. Once it's been added to the layer, when it's kind of at the time of purchase, the rendering engine would just do everything automatically, and then typically the animation will be removed as soon as it's completed.

So there's two ways you can actually add the animations to the layer, either implicitly or explicitly, and most of the time we just use the implicit animation, which basically means that every time you change a property on the layer, there's some default animation which is going to run automatically, or implicitly. It's very similar to the Cocoa stuff.

And the way this is done is by this -actionForKey: method and its kind of similar class methods. And basically, what this does is it calls this method when the property was changed, it kind of gets some default animation which, obviously, you can override, and then adds it to the layer for you.

And that often gets you about 90 percent of the way done with your animations, but some of the time you then want to create your more kind of expressive or complex or whatever explicit animation. So in those cases you would probably disable the implicit animations and then create some set of explicit animations which define the property change in more detail and then just add that directly to the layer. I mean, they're both doing, basically, the same thing, so it doesn't really matter which one you use.

And then when the animation's over, unless you tell it not to, it will just automatically disappear from the layer. You can also remove them by hand. So now, we're going to look at a little more detail in the classes that let you describe animations. So the base class is the CAAnimation, and this really just has a timing function which defines, evens things out, things like that and the delegate. The delegate lets you get messages back when the animation starts and stops, which can be useful in some cases, when chaining things or modifying the layer tree after an animation is finished or whatever.

The timing protocol, we're not going to talk a huge amount about, but basically, it's a way of describing a timing model which both layers and animations implement. So, and the timing model has things like a begin time and a duration, the repeat count, and that's about all you really need to know. So this just means that an animation has a begin time and a duration, basically.

So, the most common type of animation that we deal with are property-based animations, and this is basically because the layer model is very expressive in terms of properties, so the natural way to animate things is typically just to animate the property values. So the property animation adds, basically, just the name of the property that's being animated.

So deriving from that is the basic animation, which we also heard about earlier, and a basic animation, basically, just let's you set a fromValue and a toValue, so that you can animate the most common type of property changes, which is, for example, change my opacity from zero to one or one to zero.

For more detailed property animations, we have a Keyframe Animation class, and like most, kind of, animation, motion graphic type things, the KeyframeAnimation just lets you specify an array of values the keyframe through, and with some kind of percentage timing, so you can say that this animation has three keyframes, like an opacity from 0 to .7 to one or something, and then you can specify the relative timing of those keyframes. One other interesting thing here is that you can also not specify an array of keyframes, just kind of give it a CG path, and this way you can get kind of two dimensional motion path animations working pretty easily.

Okay, so the times when you really can't achieve the behavior you want by animating the properties of the layer, we have this transition animation subclass, and the transition is really an image-based animation, so it's something like a cross fade where you can't really achieve a cross fade just by modifying the properties of the layer, so you have to kind of go back to the pixels, and really generate those pixels and blend between them.

So there are a number of built-in types of transitions that cross fade or push left, push right, the kind of Keynote-type transitions, and also you can just give it a CI filter, or sorry, a CI filter that implements a transition. And this means you can extend this and implement your own transition types which is kind of neat.

Finally, we often find that, you know, having one animation is good, but to get the behavior we want, we really want to be able to, kind of, collect these things up and animate two properties at once, so you could just add two animations. But the nice thing about the group is that it lets you kind of define a timing model that all of those animations sit within.

So just like an animation has a begin time and a duration, so does the group, which means that when you put things inside the group, you no longer have to care so much about their, you know, begin times and end times because they're sitting within the group. So the timing, you can give the group a single timing function, which means that, you know, they will ease in and ease out in the same pattern.

Okay. So I guess that's, these are basically just the classes you normally program to, I mean you can instantiate the others but you probably won't see anything useful. Okay, so here's a very simple concrete example of programming the animation model. First of all, we're going to, you know, the same way we did with layers, we're going to create this object, BasicAnimation, and we're going to set its properties to describe what we want it to do. So in this case, we're going to say, animate the opacity property of the layer, and we're going to say animate from this value one to value zero over one second.

And that's pretty much the simplest animation you can have. Finally, once we've kind of settled the properties to describe exactly what we want, then we just add it to the layer. And then as I described earlier, the next time around the event loop, this will be sent into the rendering thread and you'll see the animation kind of happen for a second and then disappear.

Okay, so the other thing about animations that's interesting is they don't modify the layered properties directly, they modify what we call the presentation values. So when you're kind of configuring the layers what you're really defining is a model, which we then layer the animations on top of to generate the real screen values.

So, then that makes things kind of tricky because often you want to be able to say, well, where is the thing on screen now? And if it's animating, you know, you can't ask the layer because it has the model value not the presentation value, I mean the animating value.

So recently we've added these methods called -presentationLayer and -modelLayer and what -presentationLayer does is it basically lets you request a copy of the current layer you're sending this message to, but with all the animations applied for the current, for basically the current time. And so you can then get this -presentationLayer and then ask it for its opacity, and if the animation we just saw is running, then it will probably return somewhere between zero and one, not one or zero, which is the final states.

And so there are a couple, couple places where this is really, really useful. The first one is probably hit testing. The other kind of interesting thing about the -presentation Layer is that it is not just one layer, it kind of defines a presentation tree because if you ask the presentation layer for its sublayers or a superlayer, then it automatically generates a, the presentation values of those layers as well and gives them back to you.

So you can just kind of create the -presentationLayer and then say hitTest and that will actually hit test across the entire presentation tree, and then will find whichever layer in its screen position contains the point you're asking for. And so then, we go, we send that result to the -model Layer message just to get back to kind of the kind of things we know because we created them, which are the, kind of, the object model, the layer tree list.

And this works because Cocoa defines pretty nice behavior for sending messages to nil, at least for pointers So the other use is that we can ask a layer for its -presentationLayer then query the value of the property we're about to animate. So when you change the position of the layer and we go off and generate the default implicit animation, we actually set the firm value of the animation to be the position from the -presentationLayer. And that's because when you, you know, when you change the value of something we're animating, you don't want to animate from where it was, kind of half a second ago, you want to animate from where it is now. So that's that. Okay, so now we're getting on to more kind of low -level things.

So the first set of points about how to make Core Animation applications faster, is that since we sit on top of OpenGL if you know a little bit about how the graphics card works and how OpenGl kind of talks to the graphics card, you can theorize about how you might make the application faster.

So the first thing is that you want to minimize the amount of geometry that gets sent to the graphics card. So the, obviously this means minimize the number of layers in some cases or also, if you don't need to disable the edge antialising, we do it for you, because this generates more geometry.

This is typically not a big deal, but we mention it for completeness. More importantly, you really have to kind of think about overdraw. Overdraw is a measure of the number of times we touch each pixel on the screen. So for example, if you have a hundred layers composited on top of each other and the engine doesn't know they are all opaque, then it's going to draw, it's going to touch that pixel a hundred times.

And that's going to consume a lot fill rate even on monographics cards. So the way to do, o kind of fix this problem is to either implicitly tell us the layers are opaque by giving us an opaque image to put in the layer, or just, there's a method on the layer called opaque which you can kind of override to return true or set the property or whatever. And when we know the layers are opaque, we won't, we'll try not to draw things underneath it, which, you know, drastically minimizes the amount of fill rate. Similarly, you want to minimize the amount of textural image data you send to the graphics card.

So for example, if you have 1000 layers and they all have the same image, then you shouldn't generate 1000 copies of the same thing. You just use one image and set it as the contents of that layer. And then we'll create a single texture which gets past the graphics card once and assists in the texture cache.

Another kind of facet to that is that you can take things further by not saying that if I know that this layer, even though it's 1000 by 1000, if I know that when it comes out on the screen it's only going to be 10 screen pixels by 10 screen pixels, you really don't want to give us that 1000-by-1000 image, you want to give us 10-by-10 image. Because that way, you know, we're just also minimizing the amount of texture data.

Finally, this is a little harder to understand, but basically OpenGL works a lot better if you don't tell it to change all the time. So all you really need to know is that if you can, you can kind of group some model layers together. So by that I mean, if you have 100 layers all with the same image then you might want to kind of put them consecutively in the (inaudible) array cause then we don't have to kind of give OpenGL that image and then another one and then back to the first one, and you know, it's kind of latency generation kind of stuff.

So that's the kind of basic stuff, but the other big kind of performance killer that we see is that you can do a, you can render things off screen a few times, what I mean by that is that often we can't just tell OpenGL render this layer straight to the screen.

We may have to render it into an offscreen buffer or apply some kind of manipulation offscreen and then pull it back on screen. And that's, it's pretty, I mean it can kind of cause your performance to drop pretty rapidly. So there are number of things you want to avoid if you want to kind of go for this kind of top-level performance.

One of which is, you should try to avoid group capacity. Group capacity effects are where you have a number of objects all with a single capacity value applied to them. So for example, if you have a layer and it has five sublayers, but you changed the capacity of the superlayer to be .5, then really the only way, the only way we can render that correctly is by taking those 5 layers and rendering them all offscreen into a buffer and then taking that buffer and blending it back onscreen through the opacity, because otherwise you get a different result.

Similarly any use of masks can be expensive, especially mask layers where you have to render the layer offscreen to generate the mask or if you just set the mask to bounds property and the bounds of the layer isn't pixel-aligned. By which I mean it's not integral or it's rotated or something like that.

It probably doesn't come as much of a surprise that if you use Core Image filters or shadows you also incur some offscreen rendering penalty. Finally, if you get into, really into the 3D stuff, then if you try to put a 3D layer within another 3D layer, because of the way we define our rendering model that will be flattened into an offscreen buffer, you know, between those two transforms. So you really want to use one level of 3D only.

Okay, so here we have a large number of general kind of hints and tips, just things we've accumulated over the past couple of years as we've been using this stuff. The first few really deal with animation. We've found the best way to kind of think about animation then, kind of, how we write our apps is we just kind of deal with the properties first and get it kind of looking right on screen.

And then we let the implicit animations kind of do their job and we end up with something that probably looks okay, but might not be exactly what we want. So we get 90 percent of the way there just by setting properties and letting the implicit animation engine run, and then when we have to go the extra mile to get exactly what whoever specified the UI wants, then we can turn off some of the implicit animations and kind of put the explicit things we really, really know we need in their places, in their place. The way to do that is you can set properties on the transaction class to say disable implicit animations from here to here. So it's pretty, pretty common.

The next point is the timing model is something that's often overlooked, but you can use it to kind of stagger things, and kind of arrange things in time as well as space. And this lets you kind of take something that looks very simple in code, like one animation that does the same thing, and then apply it to, say, a thousand layers with slightly different time value against something that looks pretty complex. This is something that we've used a lot in the demos we showed at WWDC.

Similarly, you can take advantage of the fact we have pretty good codes to interpolate matrices, so if you want to kind of animate something through a path and space, with different orientations and different points, then you can often just kind of define the transform which represents your orientation of those points in the keyframe, and then the animation engine will take those keyframes, and kind of just interpolate between them, often in a way that's, that's pretty nice. A lot of the kind of camera animations you see in the 3D demos that we show really are just kind of interpolating matrices with nothing else actually going on.

So, that leads into the next point, which is that when we do these 3D demos, we really just -se the sublayerTransform property, which is another 4-by 4 matrix, but applies to the sublayers of the layer, and then we use that to kind apply the 3D perspective on camera transforms. It's kind of like the projection matrix on the model, view matrix, kind of combined into one if you're familiar with OpenGL.

This other type is a little kind of hard to understand, but basically, you often want to animate the removal of a layer from the scene. And so obviously, if you would just add the animation you want to kind of, you want to see for that removal to the layer, and then remove the layer, you're not going to see anything because, well, the layer's gone. So, typically, the way we do this, is we add the animation, and make sure the animation has a delegate, and then the delegate will get the notification when the animation has finished, and then we can go off and remove the layer from the layer tree.

There's one more little point to this, which is, if we just did that, then we'd probably see, excuse me, we'd probably see the removal animation run, and then a flick back to its original state, and then the layer get removed because of the kind of inherent asynchronicity in the model we have.

So, the timing protocol gives you a way to fix this, which is you can say this animation, it's going to run for some duration, and then I'm going to set this fillMode property which says even though it's over, keep applying the last state forever, and that just kind of, you know, you can animate some removal thing by, you know, animating the size to 0, or the opacity to 0, and then that final state is, is just kind of clamped in the timeline. In conjunction with this, we removedOnCompletion thing, and then once the delegate fires, because it's seen that the animation is finished, even though it's really still being applied because of the fillMode. That's when you can go off and remove it, and you don't see any glitches.

Okay. That point is pretty simple. Basically, we also, you may not think about it, but we, because a lot of the color primaries, color properties on the layers are defined as CG colors, in most places, you can take advantage of the full kind of expressiveness of the CG color, which means you can actually create a tiled pattern. For example, some image, like a checkerboard image, which repeats across the plane. And you can specify that as the color.

So, this gives you a nice kind of fairly simple way to kind of take this, take an, or take some rendered cell and repeat it across the background of the layer. Finally though, last one is just kind of a gotcha. For performance reasons, unlike some other Cocoa frameworks, we don't actually do the retain order release thing when we fetch a property for you. So, you just have to be aware of that, basically.

Okay. Okay. So, finally, basically two lines of code to put the layers on the screen. Obviously if you are using Cocoa and NSView and mixing that stuff in, it might be a little more complex, but for a lot of the kind of Core Animation only type demos. Then we'll basically have one containing View, and we'll set, we'll create some custom layer tree and then just set that layer tree as the layer of the View, and then tell the view you have to render using layers. There is another method which is the CARenderer class, and this is a way to drive the rendering of Core Animation explicitly.

Typically, you probably won't have to use this at all. There's basically two places it might be useful, one of which is if you want to drive the rendering on some external timer. So you could say, you know, render every frame and then export it to a QuickTime movie or something. Or secondly you may want to have like a full- screen OpenGL context, and just, you know, give the render of the direct OpenGL context and render into it.

And I think that's about it. So, I'm going to give a quick demo, and I thought I would go through some of the stuff we showed on the keynote, but for more of a kind of how do we do it, or did we do it perspective. So, you probably saw we had this video wall application, where I was trying to replicate the Apple TV movie, that shows when you start the Apple TV. So, the first thing we did was we built this little application that creates this mesh of layers.

And, whoops, so you can see this bares some resemblance to what we showed yesterday, but it's a lot rougher, and this is basically the first thing we had in that you can, you can have this kind of mesh, which is basically kind of a, some number of layers mapped onto the face of a cylinder, each one with its own, you know, 3D transform defining the position in space, and z position.

And then some kind of custom layout manager to define the kind of cylindrical layout, and the various parameters we thought we might want to change for the demo. So, so then we can add some color to this just by doing that, and you can see that this is kind of chunky on the edges of these things. So, the next thing is we can turn on the edge antialiasing to make that kind of clean up a lot. And then if I go back a bit, we can add the reflection layers, just to get the nice kind of, uh, pseudo-reflection look.

And so that's basically the app, and you can see we have this kind of nice 3D motion, which is like I said, is just animating the camera transform, or the sublayer transform, so when I do this, I basically just pick the position in space, you can see it actually in the bottom right-hand corner of the app.

And I use this to define my camera matrix, and then set that into the layer, and then it all just animates automatically. And I guess the real trick here is that we knew we wouldn't be able to animate, oh sorry, play back, like a thousand movies simultaneously. So, we cheated, basically.

And what we did is we generated this kind of pseudo-texture atlas kind of movie in motion, which has 144 tiles, each of which has one movie playing back in it. And it's like a 20-second repe at loop thing. And so you know that's there, and then what I can do now is I can take this movie, and drop it onto this app, and you know, you see the theatrical kind of video wall start to appear.

And so I guess the way we do this is we, there's kind of a nice little trick here which is that we can create a single QTMovie layer, and then we know that, you know, whatever the layer is, the only way it really has of communicating its contents to the render tree or the render thread is by this contents property.

So, what we actually did is then we created like, if we want a 1000, we create one QTMovie layer and 999 just normal layers, and basically just copy that contents property after we know it's been initialized to all the other layers. And so they're basically just kind of sharing this movie.

And then the other thing we did is that obviously we don't want the entire movie in every cell, so we had this kind of property on the left called contents rect, which is a way to basically take texture map of subregion out of the contents of the layer. So each layer is specifying some kind of subregion of this overall movie. And it's basically that. Obviously we still have all the nice fast motion, and all this kind of stuff.

And this is basically, I think that the entire demo is about 4000 lines of code. Most of that was to do with, you know, the Cover Flow stuff, and the searching actuallly was the main part, and the other little key bits and pieces. I mean, I think this, the thing I'm showing you here is probably only a few hundred lines of code. So, okay. I think that is that.

( Applause )

And now I think its back to Haroon to finish up.

Thank you.

Thanks. Thanks, John. So, we're actually done, so for most contact information, you want to talk, you know, talk to Alan Shaffer, our evangelist on this part, and the documentation sample goes to one of the demos that I showed earlier is already available. We'll try to get the other one available to you as soon as possible after WWDC, and got a few Labs to go to, the Core Animation Lab, and the 2D Graphics Lab, both at the same time tomorrow. You want to go to that. The Core Image one obviously, and the also the OpenGL one given how Core Animation's sort of tied to it.