Flex Effects with Pixel Bender filters, part 2.

This is the second part of a series on using Pixel Bender to create effects in Flex. In this part I'll go through making a simple filter in Pixel Bender that can be used to animate an effect in a similar way to the last post.

You can get hold of a copy of the Pixel Bender toolkit here and also get hold of a lot of good reading material to get started using it.

The filter I've made basically alters the alpha value of pixels based on their y position in the image. Using a sine function this is done in horizontal stripes to create a shutter show/hide effect. Here the code for the filter:

<languageVersion : 1.0;>
kernel ShutterFade
<   namespace : "com.as3offcuts.filters";
    vendor : "as3offcuts";
    version : 1;
    description : "shutter fade";
>


{
    //input pixel
    input image4 src;
    //output pixel
    output pixel4 dst;


    //parameter that takes the image through the effect from fully visible (0) to invisible (1)
    parameter float transition
    <
        minValue:       0.0;
        maxValue:       1.0;
        defaultValue:   0.0;
    >;


    //parameter that governs the height of the 'shutters'. The higher the number, the bigger the shutter.
    parameter float shutterHeight
    <
        minValue:       1.0;
        maxValue:       10.0;
        defaultValue:   1.0;
    >;


    void 
    evaluatePixel() 
    {
        //sample the current pixel
        pixel4 pix = sampleNearest( src, outCoord() );
        //get a base value from a sin function of the pixel's y position divided by the shutterHeight parameter
        float sinHeight = sin( outCoord().y / shutterHeight );
        //assign the base value adjusted by the transition value to the current pixel's alpha
        pix.a = sinHeight - ((transition * 3.) -2.);
        //assign the transformed pixel to the output
        dst = pix;
    }
}

 

Shutterfade source

This filter calculates a value based on the sine of the pixel's y position divided by the shutterHeight parameter. This value is then either exaggerated or reduced based on the transition parameter before being assigned to the output pixel's alpha value. This gives a graduated opaque-transparent effect in horizontal stripes going down the image.

Using this in a custom Flex effect is just a case of exporting the filter as a .pbj file and plugging it into an effect class in the same way as in the last post, and manipulating the transition parameter to create the animation.

 

Using the Flex Singleton register Pt 2/3 (Overriding Flex implementations)

This is the second in a 3 parter about the flex singleton register. This post will look at how to register your own classes with the Singleton register so you can actually use your custom implementations instead of the Flex default implementations.

The first post on the Singleton register can be found here


Registering custom implementations - the problem The last post showed that you simply use:


Singleton.registerClass("mx.managers::IPopUpManager", mx.managers.PopUpManagerImpl);  

So, in theory you just add in your own class. The problem is the Singleton.registerClass method works on a first come first serve basis - once a class is registered against an interface, no subsequent classes can be registered.

All the Flex default implementations are registered as the framework is initialized (in SystemManager.mx_internal::docFrameHandle). So, there is no chance for you to register your own implementation.


Registering custom implementations - the solution Create a custom preloader for the main Flex application. If you define your own preloader, you can register classes BEFORE the SystemManager registers the Flex classes.

 
<mx:Application  	xmlns:mx="http://www.adobe.com/2006/mxml" 	preloader="com.myDomain.preloaders.ApplicationPreloader" 	> 

And then in your preloader...

package com.myDomain.preloaders 
 { 
    import mx.core.Singleton; 
    import mx.preloaders.DownloadProgressBar; 
 
    public class ApplicationPreloader extends DownloadProgressBar
    { 
        private static var classConstructed:Boolean = staticInitializer();

        private static function staticInitializer():Boolean 		{         
            Singleton.registerClass("mx.managers::IPopUpManager",    
            com.myDomain.managers.MyCustomPopUpManagerImpl);  			 			return true; 
        } 
    } 
 }

And now we have registered our implementations before Flex does!

To tidy things up you could have a static class that does all the reigstration, and in this preloader simply call com.myDomain.manager.SingletonImplManager.register();.

The next post will look at using all this with a transparent modal background for Air applications.

Using the Flex Singleton register Pt 1/3

This is the first in a 3 part post about using the Flex Singleton register. This post will deal with what the Flex Singleton register is as well as how and why its used. The second will look at how to register your own classes with the Singleton register (not as easy as it sounds) and the third will be a real life example.

The final post will show you how to give the Alert control the ability to create a modal overlay that supports a custom chrome in Adobe Air. The big pain with a custom chrome (say a splat shape) is that the modal overlay covers the entire bounds of the window - including any transparent areas. So for irregular shapes/chrome - like a splat as a background, you get a big square slapped over the top - not ideal. What you want is ONLY the splat to be overlaid with the modal background.

By using the Singleton register and a custom implementation of the PopupManager we can add this functionality without having to create a custom Alert class. You don't have to change any of your existing app code where Alerts are used, all existing calls to Alert will now have our new and improved modal background!


The Singleton register

Flex has many singletons that are used as the default functionality for its components - the popup manager being one of them. At start up, the default implementations that flex uses are registered with the static class Singleton. When a class such as the PopupManager is first used, it will retrieve the class that defines its core functionality from the Singleton class.

The classes are registered against an interface, and it is by the interface that they are retrieved. Thus any class implementing the correct interface could be registered and used instead of the default class.

The ability to define custom implementations is a great feature of the flex framework, but is largely undocumented and support for actually overriding the default implementations is greatly lacking. However, it can be done!


Retrieving a class from the register

The PopupManager class is simply a Static class, that upon first use, will retrieve a singleton object that defines its core functionality.

Below is how the PopupManager retrieves the singleton that it will use for its core functionality. This is a static method in the PopupManager.

 
private static function get impl():IPopUpManager 
{ 
    if (!_impl) 
    { 
        _impl = IPopUpManager( 		Singleton.getInstance("mx.managers::IPopUpManager"); 
    } 

    return _impl; 
} 

The key line is :

 
Singleton.getInstance("mx.managers::IPopUpManager") 

This will perform a look up on the static class Singleton for a class that has been registered against the interface mx.managers::IPopUpManager.

If one is found, its static getInstance method is called and the instantiated singleton is returned. This instance is then used as the implementation of the PopupManagers core functionality. So, if you could register your own class against mx.managers::IPopUpManager, you could completely change how the PopupManager works!
Registering a class with the Singleton register

When the flex framework initializes, it registers each of these implementations with the static class Singleton. This simply adds the class to a class map, indexed by the interface name that it implements.

The class that is registered must adhere to the following 2 points.

  1. It must implement the interface it is registered against.
  2. It must implement a static method getInstance that returns the singleton instance of itself.


In the case of the PopupManager, the singleton class that is registered is mx.managers.PopUpManagerImpl. Its is registered against, and implements the interface mx.managers.IPopUpManager and it contains a static method getInstance as below...

 
 public static function getInstance():IPopUpManager 
 { 
    if (!instance)             instance = new PopUpManagerImpl(); 
    return instance; 
 } 
 

The registration is on a first come first serve basis, so the first class to be registered against a particular interface is stored in the Singleton registry. Any subsequent registrations for the same interface are ignored.

The PopupManger will be registered like this...

 
Singleton.registerClass("mx.managers::IPopUpManager", mx.managers.PopUpManagerImpl); 


Custom registration..... The drawback is, that all the classes are registered by the time the Flex framework has initialized, and as the register is on a first come first serve basis any subsequent registrations would be ignored.

The next post will show you how to register your own implementations before the Flex classes are registered.

Flex Effects with Pixel Bender filters, part 1.

This is the first of a two part series on using Pixel Bender filters in Flex effects. I've recently started to spend a bit of time with Pixel Bender and have found it to be a good tool for creating interesting effects and transitions in Flex. Even if you don't write any yourself, there are plenty available to use at the Pixel Bender Exchange

In this first part I'll cover an example of making an Effect and EffectInstance that extend the Flex framework and also use a Pixel Bender filter to achieve the effect. In the second part I'll cover writing a Pixel Bender filter to use with a custom effect.

I won't go over embedding and instantiating a filter as a Shader; this is well documented here. There is also a good example of animating a Pixel Bender filter here.

The Pixel Bender filter I'm going to use for this example is a dissolve effect from the BlackBookSafe sample project on Adobe Developer Connection. This filter creates a patterned dissolve effect that can be manipulated via one parameter, 'transition', which goes from 1, invisible, to 0, completely normal. Values in between giving the dissolve effect.

To turn this into an effect I have made two new classes that extend TweenEffect and TweenEffectInstance. Doing this means I take advantage of all the Flex effects functionality, and get to use the effect as a simple MXML component. The first new class, DissolveEffect, is very simple. It has two properties which it will pass onto effect instances and overrides two methods: getAffectedProperties() and initInstance(). Scroll to the bottom to see this class in its entirety.

The second class is DissolveInstance (not to be confused with mx.effects.effectClasses.DissolveInstance). This class has the Pixel Bender filter (the pbj file) embedded into it, as well as a Shader and ShaderFilter. Beyond this it is much like the FadeInstance class in that it does a small amount of validation on its properties and then uses its superclass' tween to create the desired effect. In this case the tween's value updates the transition value on the Pixel Bender filter (or more precisely the transition.value[0]), and updates the target's filters on each tween update.

 
public class DissolveEffect extends TweenEffect 
{ 
    private static var AFFECTED_PROPERTIES:Array = [ "filters" ];
 
    [Inspectable(category="General", defaultValue="undefined")] 
    public var transitionFrom:Number; 
 
    [Inspectable(category="General", defaultValue="undefined")] 
    public var transitionTo:Number; 
 
    public function DissolveEffect(target:Object=null) 
    { 
        super(target); 		 	instanceClass = DissolveInstance; 
    } 


    override public function getAffectedProperties():Array 
    { 
        return AFFECTED_PROPERTIES; 
    } 


    override protected function initInstance(instance:IEffectInstance):void 
    { 
        super.initInstance(instance); 
        var dissolveInstance:DissolveInstance = DissolveInstance(instance);
        dissolveInstance.transitionFrom = transitionFrom; 
        dissolveInstance.transitionTo = transitionTo; 
    } 
} 

 
public class DissolveInstance extends TweenEffectInstance 	
{ 
 
    [Embed(source="assets/disolve.pbj", mimeType="application/octet-stream")] 
    private var dissolveKernel:Class; 
 
    private var dissolveShader:Shader; 
    private var shaderFilter:ShaderFilter; 
 
    public var transitionFrom:Number; 
    public var transitionTo:Number; 
 
    public function DissolveInstance(target:Object) 
    { 
        super(target); 
        dissolveShader = new Shader( new dissolveKernel() ); 
        shaderFilter = new ShaderFilter( dissolveShader ); 
    } 
 
    override public function initEffect(event:Event):void 
    { 
        super.initEffect(event); 
 
        switch (event.type) 
        {	
            case "childrenCreationComplete": 
            case FlexEvent.CREATION_COMPLETE: 
            case FlexEvent.SHOW: 
            case Event.ADDED: 
            { 
                if (isNaN(transitionFrom)) 
                    transitionFrom = 1; 
                
                if (isNaN(transitionTo)) 
                    transitionTo = 0; 


                break;
            } 
            case FlexEvent.HIDE: 
            case Event.REMOVED: 
            { 
                if (isNaN(transitionFrom))
                    transitionFrom = 0; 
 
                if (isNaN(transitionTo)) 
                    transitionTo = 1; 
                break; 
            } 
        } 
    } 
 
    override public function play():void 
    { 
        super.play(); 
 
        var values:PropertyChanges = propertyChanges; 
 
        if (isNaN(transitionFrom) && isNaN(transitionTo)) 
        {	
            if (values && values.end["transition"] !== undefined) 
            { 
                transitionFrom = 1; 
                transitionTo = values.end["transition"]; 
            } 
            else 
            { 
                transitionFrom = 1; 
                transitionTo = 0; 
            } 
        } 
        else if (isNaN(transitionFrom)) 
        { 
            transitionFrom = (transitionTo == 0) ? 1 : 0; 
        } 
        else if (isNaN(transitionTo)) 
        { 
            if (values && values.end["transition"] !== undefined) 
            { 
                transitionTo = values.end["transition"]; 
            } 
            else
            { 
                transitionTo = (transitionFrom == 0) ? 1 : 0;
            } 
        }	
 
        tween = createTween(this, transitionFrom, transitionTo, duration);
        dissolveShader.data.transition.value[0] = transitionFrom;
 
        if(target.filters) 
        { 
            setTargetFilters( false, true ); 
        } 
        else 
            target.filters = [ shaderFilter ]; 
    }


    override public function onTweenUpdate(value:Object):void 
    { 
        dissolveShader.data.transition.value[0] = value; 
        setTargetFilters( true, true ); 
    } 
 
    override public function onTweenEnd(value:Object):void 
    { 
        super.onTweenEnd(value);	
        setTargetFilters( true, false ); 
    }


    private function setTargetFilters( splice:Boolean, push:Boolean ):void 
    { 
        var arr:Array = target.filters; 
        if( splice ) 
            arr.splice( target.filters.indexOf( shaderFilter ), 1 ); 
 
        if( push ) 
            arr.push( shaderFilter ); 	target.filters = arr; 
    } 
} 

Dynamically resizing AIR windows with non-resizing content.

Following on from my previous post concerning dyncamically resizing AIR windows with user resize (based on Daniel Wabyick’s example here), I wanted to cover a further modification I made; that of having the window resize dynamically, but the content stay the same.

To be more specific, I wanted a content area to remain a fixed size when the window resized dynamically, but maintain a percentage width of the area when the window was resized by the user. (If that makes no sense, download the example after the jump.)

There are two main additions made to the previous example to achieve this. Firstly was to fix the width of the non-resizing area at the start of the resize effect. This was done by adding effectStart="{mainHBox.width=mainHBox.width}" to the Resize effect.

The second part is to return the area to a percent width when the user resizes the window, so the gripperDownHandler method becomes:

 
private function gripperDownHandler():void 
{ 
    //adds an extra bit of safety incase the mouseUp occures outside the gripper      
    stage.addEventListener( MouseEvent.MOUSE_UP, gripperUpHandler ); 
    
    chrome.setStyle("top", 10); 
    chrome.setStyle("bottom", 10); 
    chrome.setStyle("left", 10); 
    chrome.setStyle("right", 10); 
    chrome.setStyle("resizeEffect", null); 
 
    mainHBox.percentWidth = 
        (mainHBox.width / (chrome.width - (mainContent.getStyle("paddingLeft")  		+
        mainContent.getStyle("paddingRight") + mainContent.borderMetrics.left 		+
        mainContent.borderMetrics.right))) 		*100;


    nativeWindow.startResize(); 
} 

The resizeHandler code has also undergone a slight tweak. It now bases the reduction target size for the chrome on the width of mainHbox. This prevents rounding errors, which could create scrollbars or slowly enlarging margins on continued resizes.

Resize Flex Image correctly and add Bitmap smoothing

If you have ever used the Flex Image component, set its minWidth / minHeight or percentWidth / percentHeight you may have noticed some strange layout issues, and that the scaled quality is not that good. You can use 3rd party Image components to get round these issues, or this very simple load handler on the image. When using these properties, the Image component itself is NOT changed, rather the content within it. So it may appear to have scaled down, but the outer bounds of the Image component (not the bitmap within it) remain the original size.

Also, when scaling the Image component, bitmap smoothing is not enabled, and as it is private you cant do anything about it - so your scaled down image is a bit jagged. There are 3rd party Image components to get round these issues, or this very simple load handler on the image...

 
private function imageLoaded(event:Event):void 
{ 
    var img:Image = event.target as Image; 

    // re set the image source to a new Bitamp that is created from the current image 
    // bitmap data, but this time with smoothing enabled 	
    img.source = new Bitmap( Bitmap(img.content).bitmapData, "auto", true ); 

    // Set the scaling of the image to 20px 	
    img.scaleX = img.scaleY = (20 / img.contentHeight); 
} 

Dynamically resizing AIR windows with user resize (gripper).

I am a big fan of Daniel Wabyick's dynamically resizing window example. ( http://www.wabysabi.com/blog/2008/01/29/example-air-app-dynamically-resizing-windows-based-on-content-area/ ). A simple and elegant solution to accommodate dynamically expanding and contracting windows in an AIR application.

I've since extended this example to fill two extra requirements. The first of these was to add a gripper that allows users to resize the window; the focus of this article. The second was to allow the window to dynamically resize, but to keep it's content the same, which I will cover in the future.

For the addition of a gripper to handle user window resizing, I've essentially added three extra elements to the original example. The main one is an Image component positioned in the bottom right that acts as the resize control. The other two elements are a mouseUp and mouseDown handler on this Image which handler the resize.

The mouseDown removes the resize effect from the main content area, locks the main content area to the window and starts the native window resize. The mouseUp then resets the resize effect and main content position.

Here are the two event handler added to the gripper component:

[sourcecode language="ActionScript3"] private function gripperDownHandler():void { //adds an extra bit of safety incase the mouseUp occures outside the gripper stage.addEventListener( MouseEvent.MOUSE_UP, gripperUpHandler ); chrome.setStyle("top", 10); chrome.setStyle("bottom", 10); chrome.setStyle("left", 10); chrome.setStyle("right", 10); chrome.setStyle("resizeEffect", null); nativeWindow.startResize(); } private function gripperUpHandler(event:MouseEvent=null):void { chrome.x = chrome.y = 10; chrome.setStyle("resizeEffect", resize); //clean up the event added in gripperUpHandler stage.removeEventListener( MouseEvent.MOUSE_UP, gripperUpHandler ); } [/sourcecode]

I've attached an example project which differs a little from the original example on Daniel Wabyick's blog, but should illustrate the principle at work.

My apologies in advance for it's ugliness.

AirResizeGripperExample

Static initialisers two ways.

Static initialisers are good ways of running code for a class before any instances of it are created. Very useful for setting up things like loggers or defining default styles for custom components. Two different methods of achieving this are outlined below.

The first method looks something like this:


 private static var classConstructed:Boolean = classConstruct();
 
private static function classConstruct():Boolean
 { 
    //do some initialising...
    return true;
 }

When the static variable classContructed gets initialised, it calls the static method classConstruct executing whatever initialisation code is needed.

The second method looks like this:

 
[Mixin] 
public class SomeClass 
{ 
    public static function init (systemManager:ISystemManager) :void 
    { 
        //do some initialising... 
    }

This method uses slightly less code as it hooks into Flex's built in initialisation. All classes that use the [Mixin] metadata tag have thier static init method called during the SystemManager's mx_internal docFrameHandler method.

How to use custom bitwise flags in Actionscript

The Alert class in AS3 is a good example of using bitwise flags to specify a configuration without having to set lots of separate Boolean flags. Its also very easy to create bitflags for yourself, which save time, code and memory! Below is an example of custom bitflags as well as an explanation of how it all works. You can have various buttons enabled in the Flex Alert - “OK”, “NO”, “Cancel” etc. Any combination can be used, and the configuration is all set via one argument. Each value is separated with the bitwise OR operator (the pipe | – not to be confused with the logical OR operator || - two pipes).

The example below would contain OK, NO and CANCEL buttons.

 
Alert.show(“My Alert message”, “My Alert tittle”, Alert.OK | Alert.NO | Alert.CANCEL );
 

Below details how this works in terms of bitwise operations, but first here is an example of how to use this in your own program.

Example of using custom bitwise flags in actionscript Create a static class to hold the values and a method to test them.

 
package 
{ 
 
public class Colours 
 { 
 
    public static const ULTRA_RED:uint 		= 1; 
    public static const RED:uint 			= 2; 
    public static const ORANGE:uint 		= 4; 
    public static const YELLOW:uint 		= 8; 
    public static const GREEN:uint			= 16; 
    public static const BLUE:uint			= 32; 
    public static const INDIGO:uint 		= 64; 
    public static const VIOLETE:uint 		= 128; 
    public static const ULTRA_VIOLETE:uint 	= 256; 
 
    //convenience const to enable all flags 
    public static const ALL:uint = ULTRA_RED | RED | ORANGE | YELLOW | GREEN | BLUE | INDIGO | VIOLETE | ULTRA_VIOLETE; 
 
    public static function test(flags:uint, testFlag:uint):Boolean 
    { 
        return (flags & testFlag) == testFlag;
    } 
 } 
} 

Now, you can pass a combination of flags around as one single argument. The flags are combined using the bitwise OR operator.

 
var chosenColours:uint = Colours.RED | Colours.BLUE | Colours.VIOLETE; 

Then later test to see if the flag you want is in that single argument.

 
if ( Colours.test(chosenColours, Colours.RED) ) 
    trace(“We have RED”); 
else 
    trace(“We don’t have RED”); 

Note the Colours.ALL const, which is just a convenient way to enable all the flags in one go. 

And that's it. Makes life very simple, less method arguments, less var declaration, less database columns if you store a configuration, less memory used. Very simple to implement and very useful!

How it works - creating Each of the constants that define the flags Colours.RED, Colours.YELLOW etc are all integers. The separate flags must be multiples of 2 (which will become clearer later), so they would be 1,2,4,8,16,32 etc. The bitwise OR looks at the binary representation of each integer and analyses each bit of each integer in turn. Each bit is treated as a Boolean flag. If the bit is 1, its on, if its 0 its off. The bitwise OR will look at all the corresponding bits of each value in the list, starting with the first bit, then the second etc. If any of the bits are 1, the resulting bit for that position is 1, if ALL are 0 the resulting bit for that position is 0.
        0001  ( decimal 1 )         0010  ( decimal 2 )         1000  ( decimal 8 ) Bitwise OR =         1011  ( decimal 11 )
So, looking down each column of bits, the OR checks if any are 1, if so, the resulting bit is 1, else its 0. So the output of ( 1 | 2 | 8 ) is 1011,which is decimal 11. As the integers are multiples of 2 you don’t get multiple “1” bits in the binary representation of any number so only 1 column is ever marked as “on” by any flag – as in the example above. If you added 0110 ( binary 10 ) to the example above it would end up with 2 columns marked as "on" for one flag, which would break the system as you could not then calculate if the resulting bit flag contained a specific flag, as explained below.


How it works - testing Now you have one value that represents multiple flags. The next step is to check if it contains a particular flag. This is very similar, except you reverse the process and use the bitwise operator AND (the ampersand &, not to be confused with the logical AND &&) This looks at the columns of bits, and if ALL of them are 1, the result is 1, if not its 0. In the same way, as the columns are unique due to multiples of 2, we can check if the combined integer contains our value.
        1011 (decimal 11 - our combined flags)         0010 (decimal 2 - the flag to check for) Bitwise AND =         0010 (decimal 2)
As only the 2nd (from right) column contined both “On” bits, the result is 0010, which is our decimal 2, the value we wanted to check! So you can easily check to see if your value is in the combined flags by doing the following.



var hasValue:Boolean = ((flags & value) == value)

Very useful stuff!

AutoComplete component sizing.

The Flex Components AutoComplete ( Link ) offers a great auto suggestion text input component, which often makes for a better experience than a combo box or list. What it didn't do was resize quite how a wanted it to.

I was using the AutoComplete component as the auto-resizing part of a horizontal panel in an AIR application. When the window was resized by the user, the AutoComplete would enlarge or shrink to fit, down a minimum size set on the window.

The problem was that I couldn't seem to get the AutoComplete to fit without scrollbars appearing. After a bit of digging I found the minimum width gets set to the longest item in the data provider in the measure method of ComboBase. This was exacerbated by the long items in the data provider I was using, forcing scroll bars onto any reasonable size of window.

Extending AutoComplete and overriding measure with the following fixes the problem, and hasn't given me any issues so far.

 
override protected function measure():void 
{ 
    measuredWidth = mx.core.UIComponent.DEFAULT_MEASURED_WIDTH; 
    measuredHeight = UIComponent.DEFAULT_MEASURED_HEIGHT; 
    measuredMinWidth = UIComponent.DEFAULT_MEASURED_MIN_WIDTH;
    measuredMinHeight = UIComponent.DEFAULT_MEASURED_MIN_HEIGHT; 
} 

By not calling super and setting the four properties above then the component takes on the default minimum width of 40 and re-flows as expected. Obviously some of the items in the drop down may be cut off, but the text in the input field is draggable, so it's always possible to see all of it one way or another. A future improvement to this might be to include a tool-tip rollover to truncated drop down items.

I might improve this if I reuse the component in the future - maybe include some measurement logic similar to TextInput, or just some provision for borders and padding. In it's current application it works though, so I might just leave well alone!