Developing Android Applications with Adobe AIR [85]
Keep your display list fairly shallow and narrow.
The renderer needs to traverse the display list and compute the rendering output for every vector-based object. Matrices on the same branch get concatenated. This is the expected management of nested objects: if a Sprite contains another Sprite, the child position is set in relation to its parent.
Node Relationship
This is the most important point for successful use of caching. Caching the wrong objects may result in confusingly slow performance.
The cacheAsBitmapMatrix property must be set on the moving object, not on its container. If you set it on the parent, you create an unnecessarily larger bitmap. Most importantly, if the container has other children that change, the bitmap needs to be redrawn and the caching benefit is lost.
Let’s use an example. The parent node, the black box shown in the following figures, has two children, a green circle and a red square. They are all vector graphics as indicated by the points.
In the first scenario (depicted in Figure 14-2), cacheAsBitmapMatrix is set on the parent node. The texture includes its children. A bitmap is created and used for any transformation, like the rotation in the figure, without having to perform expensive vector rasterization. This is a good caching practice:
var box:Sprite = new Sprite();
var square:Shape = new Shape();
var circle:Shape = new Shape();
// draw all three items using the drawing API
box.cacheAsBitmap = true;
box.cacheAsBitmapMatrix = new Matrix();
box.rotation = 15;
Figure 14-2. Caching and transformation on the parent only
In the second scenario (depicted in Figure 14-3), cacheAsBitmapMatrix is still on the parent node. Let’s add some interactivity to make the circle larger when clicked. This is a bad use of caching because the circle needs to be rerasterized along with its parent and sibling because they share the same texture:
// change datatype so the display object can receive a mouse event
var circle:Sprite = new Sprite();
// draw items using the drawing API
circle.addEventListener(MouseEvent.CLICK, bigMe);
function bigMe(event:MouseEvent):void {
var leaf:Sprite = event.currentTarget as Sprite;
leaf.scaleX += .20;
leaf.scaleY += .20;
}
Figure 14-3. Caching on the parent, but transformation on the children
In the third scenario (depicted in Figure 14-4), cacheAsBitmapMatrix is set, not on the parent, but on the children. When the circle is rescaled, its bitmap copy can be used instead of rasterization. In fact, both children can be cached for future animation. This is a good use of caching:
// change datatype so they can receive mouse events
var square:Sprite = new Sprite();
var circle:Sprite = new Sprite();
// draw items using the drawing API
square.addEventListener(MouseEvent.CLICK, bigMe);
circle.addEventListener(MouseEvent.CLICK, bigMe);
var myMatrix:Matrix = new Matrix();
square.cacheAsBitmap = true;
square.cacheAsBitmapMatrix = myMatrix;
circle.cacheAsBitmap = true;
circle.cacheAsBitmapMatrix = myMatrix;
function bigMe(event:MouseEvent):void {
var leaf:Sprite = event.currentTarget as Sprite;
leaf.scaleX += .20;
leaf.scaleY += .20;
}
Figure 14-4. Caching and transformation on each individual child
The limitation with using GPU rendering occurs when a parent and its children need to have independent animations as demonstrated earlier. If you cannot break the parent-child structure, stay with vector rendering.
MovieClip with Multiple Frames
Neither cacheAsBitmap nor cacheAsBitmapMatrix works for a MovieClip with multiple frames. If you cache the art on the first frame, as the play head moves, the old bitmap is discarded and the new frame needs to be rasterized again. This is the case even if the animation is a rotation or a position change.
GPU rendering is not the technique for such situations. Instead, load your MovieClip without adding it to the display list. Traverse through its timeline and copy each frame to a bitmap using the BitmapData.draw method. Then display one frame at a time using the BitmapData.copyPixels