Building an AS3 component framework: Deferred Rendering

Posted on July 2, 02008
Filed Under DaVinci, Development, Flash

Every component framework I’ve ever seen implements deferred rendering. The aim of this feature is to optimize the redrawing of a component so that it does not perform any unnecessary operations.

The Problem
Component properties can change many times during a frame and redrawing them every time this happens is wasteful. The optimal solution is to redraw the component once per frame and only if one or more properties have changed. This process of batching state changes for later rendering is called 'invalidation'.

There is a second issue to be aware of when dealing with redrawing and it’s of critical importance during the instantiation process. The component does not have access to the stage until it has been added to the active DisplayList.

The Solution
Every component has a draw() function which when called renders the component based upon its current internal state. Instead of calling draw() every time a property changes, the component caches the value of the property and calls invalidate() instead. This function schedules a draw() event at the next available opportunity. With this technique the properties can be changed hundreds of times a frame without any significant drop in performance.

There is two common strategies for implementing invalidation in AS3. I compared both of these when I looked ‘Inside the MinimalComps’ and concluded that unless I can find a fail-safe way of using stage.invalidate() then I'm going to have to go with the old ENTER_FRAME event. Here’s the process flow for a typical component: It can be instantiated by either placing it on the timeline or by using the new() command in code.

1. Firstly the component constructor runs. This calls the init() function which initializes the start-up state of the component.

2. When the component is added to the stage the resume() function gets called. This function starts up any internal listeners then calls the draw() function which redraws the component based upon its internal state.

3. Removing a component from the stage (by code or by moving the timeline playhead forces the suspend() function to be called. This freezes the component whilst it is not on the DisplayList. That means no more realtime 3D hogging the processor and no more mp3s playing from nowhere!

The invalidate() and draw() functions are currently both protected. I can’t think of a good reason for making them public right now. They are both housekeeping functions that get used by the public properties and methods of the individual component.

The memory management methods however, suspend(), resume() and destroy() are all public so they can be called by parents or managers at any time.

The Benefits
Deferred Rendering will greatly improve the overall performance of your application.

The Code

package org.computus.core
{
  import flash.events.Event;
  import flash.display.MovieClip;

  public class AbstractComponent extends MovieClip
  {

  // ------------------------------------------
  // PROPERTIES

    // isSuspended starts as true as the component is off stage
    protected var _isSuspended:Boolean = true;

  // ------------------------------------------
  // CONSTRUCTOR

    public function AbstractComponent():void
    {
      super();
      init();
      if (stage) { resume() }
    }

  // ------------------------------------------
  // MEMORY MANAGEMENT

    protected function init():void
    {
      // concrete classes that override this function should call super.init()
      // n.b. These events require Flash Player 9.0.28.0
      addEventListener(Event.ADDED_TO_STAGE, onAddedToStage, false, 0, true);
      addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage, false, 0, true);

      // initialise component here.
      // no need to call draw() as it will be called when component is added to the stage.
    }

    public function destroy():void
    {
      // concrete classes that override this function should call super.destroy()
      // remove all listeners here
      suspend();
      removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
      removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
    }

    public function suspend():void
    {
      // concrete classes that override this function should call super.suspend()

      // suspend all processes
      removeEventListener(Event.ENTER_FRAME, onInvalidate)
      _isSuspended = true;
    }

    public function resume():void
    {
      // concrete classes that override this function should call super.resume()
      // resume all processes
      _isSuspended = false;
      draw();
    }

    public function get isSuspended():Boolean
    {
      return _isSuspended;
    }

  // ------------------------------------------
  // EVENTS

    private function onInvalidate(e:Event):void
    {
      removeEventListener(Event.ENTER_FRAME, onInvalidate);
      draw();
    }

    private function onAddedToStage(e:Event):void
    {
      resume()
    }

    private function onRemovedFromStage(e:Event):void
    {
      suspend()
    }

  // ------------------------------------------
  // DRAW

    protected function invalidate():void
    {
      addEventListener(Event.ENTER_FRAME, onInvalidate, false, 0, true);
    }

    protected function draw():void
    {
      // concrete classes should override this function
      // redraw component state
    }
  }
}
Share/Bookmark

Related Journal Entries

  1. Component framework July update
  2. AS3 Component: NumberStepper
  3. AS3 component: NextPreviousButton
  4. The project architecture
  5. Building an AS3 component framework: Suspend and Resume
  6. Building an AS3 component framework: Events and Inheritance
  7. Building an AS3 component framework: Garbage Management
  8. Inside the Bit-101 MinimalComps
  9. Building an AS3 component framework: Planning
  10. Choosing an AS3 component framework
  11. AS3 Component: TimeStepper
  12. The Computus Engine on Google Code
  13. Building an AS3 component framework: The Finished BaseComponent Class
  14. Creating a main preloader in Flash CS3
  15. Projects update March 2009

Comments

Leave a Comment

If you would like to make a comment, please fill out the form below.

Name (required)

Email (required)

Website

Comments