Archive for the 'Code' Category
Flex/Flash Builder + OS X 10.6 (Snow Leopard) SWT Carbon Errors
If you are a big user of Ant like I am, then you have probably encountered some problems with some of your Ant scripts when launching them from within Flex or Flash Builder under OS X 10.6 (Snow Leopard). In a nutshell, the problem is due to OS X 10.6 defaulting to 64-bit VMs, no longer supporting older Carbon apps. If you see an error in your Eclipse console complaining about missing ’swt-carbon’ or incompatibility with the 64-bit VM - read on for a simple fix.
In the Eclipse file menu, browse to Window > Preferences… > Java > Installed JREs. If JVM 1.6.0 is not selected as the default, go ahead and select it. Next, highlight JVM 1.6.0 and click the ‘Edit…’ button. In the window that appears, there should be an input box for ‘Default VM Arguments’. Enter the following argument (without the quotation marks): ‘-d32′. Press ‘OK’ to save the changes and then go ahead and restart the application.
If you followed the instructions correctly, you should no longer encounter these types of errors when running your Ant script(s).
1 commentDealing With ‘Unable To Resolve Asset For Transcoding’ Errors
Awhile back, I wrote a similar post titled Cure For The ‘Unable To Resolve Asset For Transcoding’ Compiler Error. Though old, the post continues to get a lot of hits, so I thought I would post another entry on a similar issue which you may have encountered.
Have you ever been working on a project and went to do a build, only to be slapped with a bunch of ‘Unable To Resolve (asset path/name) For Transcoding’ errors? Perhaps you are reading this post because it just happened to you and you have no idea why. Continue reading.
The reason this occurs is because you have some assets somewhere in your project that are now missing; whether it be because they were moved and their references in your CSS were never updated or possibly because they were deleted by mistake. Whatever the reason, they are no longer at the location specified in your CSS and that is causing the entire embed process to fail. The tricky part is figuring out which assets are the problems. Unlike the rest of errors, the actual problematic assets will read ‘Unable To Transcode (asset path/name)’. If you do not see any errors with this message in your Eclipse ‘Problems’ panel, it is because it only shows 100 errors by default and you may have many more than that depending on the size of your project.
To change this, click the little arrow in the top right-hand corner of the panel and select ‘Preferences…’ from the menu. In the pop up window that appears, find the line that reads ‘Limit visible items per group to:’ and change the number next to it from 100 to a larger value, such as 200. Repeat this process if you still aren’t seeing all of the errors. Once they are all visible, you should be able to find the errors which call out the assets that are causing the problem. Make the appropriate changes and re-build; your problems should be gone at this point.
No commentsFlex VideoDisplay Tweaks
If you have ever worked with the Flex VideoDisplay component, you are no doubt aware of the fact that its long list of conveniences come at the expense of some limitations and bugs. While the intention of this post is to cover a simple workaround for a few issues, I encourage you to share additional bugs and workarounds that you have had to implement in the comments below.
NOTE: Before getting started, I highly recommend that the minimum version of the Flex SDK that you target be 3.2.0.3958 due to a variety of video related fixes have been made in builds prior to this.
The issue that I would like to address is when you attempt to play a list of videos using the VideoDisplay component. What happens is that upon the 'complete' event being dispatched, you then update the component's 'source' property to reference the next video that you would like to play. Upon doing so, you will likely find that the component falls into an unresponsive state. More specifically the 'stateResponsive' property gets locked up with a value of 'false', rendering the object useless. If you do some Googeling, you will find posts that describe this occurrence and others that also occur as the result of race conditions internally within the component.
Fortunately, you can bypass this problem fairly simply by disabling a few things and creating a subclass of VideoDisplay. While you're at it, you can add an implicit getter and setter for toggling video smoothing; something that was unfortunately left out of the VideoDisplay API for some reason. Let's begin by examining a simple subclass:
-
package
-
{
-
import mx.controls.VideoDisplay;
-
-
public class MyVideoDisplay extends VideoDisplay
-
{
-
[Bindable]
-
override public function get source():String
-
{
-
return super.source;
-
}
-
-
override public function set source(value:String):void
-
{
-
super.source = value;
-
-
play();
-
}
-
-
public function MyVideoDisplay()
-
{
-
super();
-
}
-
}
-
}
All I am doing here is overriding the implicit getter/setter for 'source' and adding a call to the 'play' method each time the source it set. Now in your view, be sure to disable 'autoPlay' and 'autoRewind':
-
<local:MyVideoDisplay
-
id="myVideoDisplay"
-
autoPlay="false"
-
autoRewind="false"
-
source="{ModelLocator.myVideoModel.currentVideo.url}" />
If you prefer, this could be handled in your subclass instead; for the sake of example, I am showing it in MXML. This is an important step though; it is the combination of the additions in the subclass and these two settings being disabled that will allow your video list to play one-by-one without encountering the bug.
Now, since you have a subclass ready to go, why not add access to the smoothing capabilities of the underlying VideoPlayer? To do so, you will need to gain access to the VideoPlayer instance by using the 'mx_internal' namespace. Simply add a getter/setter for smoothing to your class, then reference the example below for actually applying the changes:
-
package
-
{
-
import flash.events.Event;
-
-
import mx.controls.VideoDisplay;
-
import mx.core.mx_internal;
-
-
use namespace mx_internal;
-
-
[Event(name="smoothingChanged", type="flash.events.Event")]
-
-
public class MyVideoDisplay extends VideoDisplay
-
{
-
private var _smoothing:Boolean;
-
-
private var _smoothingChanged:Boolean;
-
-
[Bindable("smoothingChanged")]
-
public function get smoothing():Boolean
-
{
-
return _smoothing;
-
}
-
-
public function set smoothing(value:Boolean):void
-
{
-
if (_smoothing != value)
-
{
-
_smoothing = value;
-
_smoothingChanged = true;
-
-
invalidateProperties();
-
-
dispatchEvent(new Event("smoothingChanged"));
-
}
-
}
-
-
[Bindable]
-
override public function get source():String
-
{
-
return super.source;
-
}
-
-
override public function set source(value:String):void
-
{
-
super.source = value;
-
-
play();
-
}
-
-
public function MyVideoDisplay()
-
{
-
super();
-
}
-
-
override protected function commitProperties():void
-
{
-
super.commitProperties();
-
-
if (_smoothingChanged)
-
{
-
if (mx_internal::videoPlayer)
-
{
-
_smoothingChanged = false;
-
-
mx_internal::videoPlayer.smoothing = _smoothing;
-
}
-
}
-
}
-
}
-
}
Two birds with one stone, but a shame that any of this was necessary in the first place. As I mentioned earlier, if you have any other VideoDisplay workarounds for these issues or others and you would like to share them, please do so in the comments below.
5 commentsFP10: Generic Number Crunching Via Pixel Bender - Part 2
Many of you have expressed concern regarding the Flash implementation of Pixel Bender using the CPU rather than the GPU like Photoshop and After Effects. A lot has changed since my first post on the topic of generic number crunching; though you can certainly refer to my previous post for reference on how to get started, I have some additional points that I would like to make clear:
1.) Compared to pure AS3, a Pixel Bender kernel will be up to X number of times faster; X being the number of CPU cores the machine it is running on has. It isn’t always a 1:1 performance gain though; I would say on average that a complex task will be around 3x faster than the optimized AS equivalent. Keep in mind that you are also working with 32-bit floating point values in Pixel Bender, where as in AS something like BitmapData is limited to only 8-bit uints per channel.
2.) Even if Flash had full GPU support, the CPU would still beat it out in some cases. A good example of this is when you are using a kernel to handle some generic number crunching. Reading back data from the GPU rather than just displaying it is a very slow process. The mindset that GPU support would be the answer to all of our problems in Flash is simply not true.
3.) Not every task will see a performance gain by moving calculations from AS to a PB kernel. In general, operations to a bitmap or bitmaps will almost always be faster, but in the case of generic number crunching, it depends on the complexity of the math taking place. Simply deferring your cross product calculations from AS to a PB kernel is going to be the same speed or even a bit slower in some cases. The biggest advantage to deferring your complex algorithms to a PB kernel is that you can avoid UI lag while the shader job is processing. This is due to the fact that the calculations are taking place on a different thread than ActionScript. Finding the right balance between AS and PB is simply a matter of experimentation and testing.
4.) PB rendering tasks are split up by row and delegated to each core on a multi-core machine. If the height of an input is one, only one core will be used. In other words, be smart about how you configure the heights of your shader jobs; more CPUs crunching your numbers means faster performance.
5.) There are limitations in the PB Toolkit that prevent you from exporting byte code with certain output types (currently, these problems revolve around limitations with GPUs). These limitations force you to either work with collections that are a width of a certain multiple or do some sort of filtering process in AS after the shader job has completed. The PB command-line utility that Adobe will be releasing soon addresses these limitations by allowing you to export byte code for everything that FP10 supports, thus alleviating the need to do workarounds.
As I have mentioned in previous posts, I will be covering all of this information and a whole lot more in my session 'Pixel Bender Unleashed' at Adobe MAX this November. Seats are starting to fill up, so if you haven't already setup your MAX schedule you should definitely do that before you miss out on any of the big sessions that you wish to attend.
On a final note - I haven't gotten around to doing the iPhone tutorial for Flash developers yet, but will be doing so this week. Look for a post on it soon!
1 commentPixel Bender: AIF_FLASH_TARGET
Something nice that recently appeared in the Pixel Bender spec is the preprocessor symbol AIF_FLASH_TARGET. When testing under normal conditions, AIF_FLASH_TARGET is set to a value of 0. With Flash warnings enabled, AIF_FLASH_TARGET is set to a value of 1. Testing against this allows you to use methods that are not currently supported by Flash Player while testing in the Toolkit, but still produce a shader that is Flash compatible.
To better understand this, create a simple procedural shader such as the one below:
-
<languageVersion : 1.0;>
-
-
kernel ColorShader
-
<
-
namespace : "Boostworthy::Shaders";
-
vendor : "Ryan Taylor";
-
version : 1;
-
description : "Example procedural shader that uses the AIF_FLASH_TARGET preprocessor symbol.";
-
>
-
{
-
parameter float4 color
-
<
-
minValue : float4(0.0, 0.0, 0.0, 0.0);
-
maxValue : float4(1.0, 1.0, 1.0, 1.0);
-
defaultValue : float4(0.0, 0.0, 0.0, 1.0);
-
description : "RGBA color value of the solid fill.";
-
>;
-
-
output pixel4 dst;
-
-
region
-
generated()
-
{
-
return region(float4(0.0, 0.0, 200.0, 200.0));
-
}
-
-
void
-
evaluatePixel()
-
{
-
dst = color;
-
}
-
}
If you were to run that shader with Flash warnings disabled, you would have a 200x200 box with a RGBA parameter that sets the color of the solid fill. Now enable Flash warnings and run the shader once more. This time around, an error will be thrown telling you that only the evaluatePixels method is supported in Flash.
Now insert a statement that checks the AIF_FLASH_TARGET symbol:
-
<languageVersion : 1.0;>
-
-
kernel ColorShader
-
<
-
namespace : "Boostworthy::Shaders";
-
vendor : "Ryan Taylor";
-
version : 1;
-
description : "Example procedural shader that uses the AIF_FLASH_TARGET preprocessor symbol.";
-
>
-
{
-
parameter float4 color
-
<
-
minValue : float4(0.0, 0.0, 0.0, 0.0);
-
maxValue : float4(1.0, 1.0, 1.0, 1.0);
-
defaultValue : float4(0.0, 0.0, 0.0, 1.0);
-
description : "RGBA color value of the solid fill.";
-
>;
-
-
output pixel4 dst;
-
-
#if !AIF_FLASH_TARGET
-
-
region
-
generated()
-
{
-
return region(float4(0.0, 0.0, 200.0, 200.0));
-
}
-
-
#endif
-
-
void
-
evaluatePixel()
-
{
-
dst = color;
-
}
-
}
Once again, try running the shader with Flash warnings on and off. Notice that no errors were thrown while Flash warnings were enabled. Also notice that nothing is being rendered in the display panel. This is due to the fact that the generated method is not being included. This is ok though, as use of the drawing API in Flash to create a shader fill will work just fine.
Now for the bad news - it seems that there is currently a bug with the Pixel Bender Toolkit in which the value of AIF_FLASH_TARGET is not set to 1 while exporting to byte code for Flash. Doh! I have already entered a bug for this issue, so rest assured that it will likely be fixed by the final release of the Toolkit. Nonetheless, I wanted to post about this functionality anyway since it is essential to creating shaders that work as desired in Photoshop and After Effects, as well as in Flash.
No commentsAnt: Launch Flash Player Target For Mac
Awhile ago I wrote an article about the use of Ant for handling common Flash-related development tasks. Unfortunately there has always been a problem with launching a SWF file into the standalone Flash Player on a Mac due to the fact that '.app' files are actually folders. Fortunately, you can get around this using the 'open' command as seen below:
-
<!-- LAUNCH MAIN SWF -->
-
<target name="launchMain" description="Launches the main SWF into the standalone Flash Player.">
-
<echo>Launching '${bin}/main.swf'...</echo>
-
<exec executable="open" vmlauncher="true" spawn="false" failonerror="true">
-
<arg line="-a '${flashPlayer}'" />
-
<arg line="${bin}/main.swf" />
-
</exec>
-
</target>
Where '${flashPlayer}' is a property pointing towards a standalone version of Flash Player, for instance:
-
<property name="flashPlayer" value="/Applications/Adobe Flash CS3/Players/Debug/Flash Player.app" />
With more and more Flash applications being tied into the browser for deep-linking, etc. it has become a more common need to launch the application inside of a HTML page; however I wanted to share this because I do feel as if it still has some value.
7 commentsFP10: ZBuffer Class For Sorting Depths
Flash Player 10 DisplayObjects include some very basic 3D properties, such as 'z' and 'rotationZ'. These properties simply handle basic affine transformations behind the scenes for you; a collection of DisplayObjects aren't actually getting projected into a scene per say. What this means is that a DisplayObject's 'z' property does not affect it's depth inside of a DisplayObjectContainer. Let's say that you have two DisplayObjects, childA and childB respectively, and childA is at depth index 0 and childB is at index 1. Even if childB is further down the Z axis than childA, childA will still be rendered behind it.
Since plenty of developers will likely take advantage of this basic 3D support to create a variety of simple effects (such as carousels), I decided to make a 'ZBuffer' class for conveniently handling the depth issue. My implementation is very straightforward; you have two methods to choose from - 'ZBuffer.sort' and 'ZBuffer.recursiveSort'. The 'sort' method accepts a DisplayObjectContainer and will loop through it's children and sort their depths accordingly based on their locations along the Z axis. The 'recursiveSort' method does the exact same thing, except it will also recursively sort each child's children if the child is a DisplayObjectContainer as well.
Here is a brief example of the 'ZBuffer' class in use:
-
// Create a new 'ZBuffer' instance.
-
-
var zBuffer:ZBuffer = new ZBuffer();
-
-
// Create and draw graphics for a few planes.
-
// Offset their positions so that each one is visible.
-
-
var plane1:Sprite = new Sprite();
-
var plane2:Sprite = new Sprite();
-
var plane3:Sprite = new Sprite();
-
-
plane1.graphics.beginFill(0xFF0000);
-
plane1.graphics.drawRect(0, 0, 200, 200);
-
plane1.graphics.endFill();
-
-
plane2.graphics.beginFill(0x00FF00);
-
plane2.graphics.drawRect(0, 0, 200, 200);
-
plane2.graphics.endFill();
-
-
plane3.graphics.beginFill(0x0000FF);
-
plane3.graphics.drawRect(0, 0, 200, 200);
-
plane3.graphics.endFill();
-
-
plane1.x = 80;
-
plane1.y = 50;
-
plane1.z = 100;
-
-
plane2.x = 150;
-
plane2.y = 100;
-
plane2.z = 200;
-
-
plane3.x = 220;
-
plane3.y = 150;
-
plane3.z = 20;
-
-
// Add the planes to the display container.
-
-
addChild(plane1);
-
addChild(plane2);
-
addChild(plane3);
-
-
// Sort the display container's children (the planes).
-
// The planes will now display at the correct depth
-
// based on their location along the Z axis.
-
-
zBuffer.sort(this);
Included with the source files is an example which is similar to the example above, except the planes are animated to better demonstrate the sorting.
View the 'ZBuffer' example (Flash Player 10 required)
As usual, the class is licensed under the MIT license...so you can use it however you please.
Download 'boostworthy_zbuffer_src.zip'
Enjoy!
1 commentFP10: Pixel Bender AlphaMatteComposite
In most image editing applications, the use of an alpha matte for masking a layer or object is a common practice. Flash works a little differently; you can still create masks, but they simply perform a boolean AND (clipping) operation on the object. Flash 8 introduced the ability to take things a step further and include a mask's alpha in the masking process. Below is an example of this in action:
-
// Create a 300 x 300 box with a color fill.
-
-
var container:Sprite = new Sprite();
-
container.graphics.beginFill(0x008822, 1);
-
container.graphics.drawRect(0, 0, 300, 300);
-
container.graphics.endFill();
-
addChild(container);
-
-
// Create a matrix for defining the gradient region.
-
-
var gradientMatrix:Matrix = new Matrix();
-
gradientMatrix.createGradientBox(300, 300, 0, 0, 0);
-
-
// Create a 300 x 300 box with a gradient fill.
-
// Notice that the alpha is being ramped down from
-
// left to right ([1, 0]).
-
-
var containerMask:Sprite = new Sprite();
-
containerMask.graphics.beginGradientFill(GradientType.LINEAR, [0xFFFFFF, 0x000000], [1, 0], [0, 255], gradientMatrix);
-
containerMask.graphics.drawRect(0, 0, 300, 300);
-
containerMask.graphics.endFill();
-
addChild(containerMask);
-
-
// Note: This step is required. Both objects must be
-
// using runtime bitmap caching in order for an alpha
-
// channel to be used for masking. If this step is not
-
// taken, the mask's shape will be used as a clipping
-
// mask and alpha will be ignored.
-
-
container.cacheAsBitmap = true;
-
containerMask.cacheAsBitmap = true;
-
-
// Apply the container mask to the container.
-
-
container.mask = containerMask;
In the past, the shape of the gradient alone would mask the container. Notice in the example that runtime bitmap caching ('cacheAsBitmap') is enabled for both objects - this is what allows the additional alpha processing to be done.
Flash 8 also introduced blend modes and they presented another option for performing more complex masking effects. By creating a container object and then setting its blend mode to 'LAYER', you are forcing the creation of a transparency group for that object. You can then create foreground and background display objects inside of the container and set the foreground's blend mode to 'ALPHA'. This will result in the background image inheriting the alpha values of each pixel from the foreground layer. As a result, the background layer will be masked by the foreground layer. Here is an example:
-
// Create a container for storing the background
-
// and foreground objects.
-
-
var container:Sprite = new Sprite();
-
addChild(container);
-
-
// Create a 300 x 300 box with a color fill.
-
-
var containerBackground:Sprite = new Sprite();
-
containerBackground.graphics.beginFill(0x008822, 1);
-
containerBackground.graphics.drawRect(0, 0, 300, 300);
-
containerBackground.graphics.endFill();
-
container.addChildAt(containerBackground, 0);
-
-
// Create a matrix for defining the gradient region.
-
-
var gradientMatrix:Matrix = new Matrix();
-
gradientMatrix.createGradientBox(300, 300, 0, 0, 0);
-
-
// Create a 300 x 300 box with a gradient fill.
-
-
var containerForeground:Sprite = new Sprite();
-
containerForeground.graphics.beginGradientFill(GradientType.LINEAR, [0xFFFFFF, 0x000000], [1, 0], [0, 255], gradientMatrix);
-
containerForeground.graphics.drawRect(0, 0, 300, 300);
-
containerForeground.graphics.endFill();
-
container.addChildAt(containerForeground, 1);
-
-
// The container's blend mode must be set to BlendMode.LAYER
-
// in order for it's child objects to be able to use BlendMode.ALPHA.
-
// This operation causes the background object's alpha to be replaced
-
// by the alpha of the corresponding pixels in the foreground object.
-
-
container.blendMode = BlendMode.LAYER;
-
containerForeground.blendMode = BlendMode.ALPHA;
That brings us to modern day Flash 10 development. Since we now have Pixel Bender at our disposal, we can create our own tools for compositing. Something that I have been wanting in Flash for many years is the ability to mask an image using an alpha matte, as you would in Photoshop or After Effects. For those of you who aren't familiar with what I am describing - an alpha matte is a grayscale image in which a pixel that is completely white represents 100% alpha, a pixel that is completely black represents 0% alpha, and everything in between represents smooth steps from 0% to 100%. Technically, you could accomplish this in the past by operating on BitmapData objects, but that can be costly and undesirable in many situations.
My solution was to create a simple Pixel Bender kernel for handling alpha matte compositing. It accepts two inputs; one for the source image and one for the alpha matte. The output is the resulting masked version of the source image. The inputs are both typed as image4 for maximum compatibility with Flash (for instance, using a shader as a blend mode requires two image4 inputs).
Here is the source:
-
// *****************************************************************************************
-
// AlphaMatteComposite.pbk
-
//
-
// Copyright (c) 2008 Ryan Taylor | http://www.boostworthy.com
-
//
-
// Permission is hereby granted, free of charge, to any person
-
// obtaining a copy of this software and associated documentation
-
// files (the "Software"), to deal in the Software without
-
// restriction, including without limitation the rights to use,
-
// copy, modify, merge, publish, distribute, sublicense, and/or sell
-
// copies of the Software, and to permit persons to whom the
-
// Software is furnished to do so, subject to the following
-
// conditions:
-
//
-
// The above copyright notice and this permission notice shall be
-
// included in all copies or substantial portions of the Software.
-
//
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-
// OTHER DEALINGS IN THE SOFTWARE.
-
// *****************************************************************************************
-
//
-
// + + + + + + + + +
-
//
-
// *****************************************************************************************
-
-
<languageVersion : 1.0;>
-
-
kernel AlphaMatteComposite
-
<
-
namespace : "Boostworthy::Filters";
-
vendor : "Ryan Taylor";
-
version : 1;
-
description : "Given a source image and grayscale matte which represents alpha, a composite of the two will result in a masked source image.";
-
>
-
{
-
input image4 source;
-
input image4 alphaMatte;
-
output pixel4 result;
-
-
void evaluatePixel()
-
{
-
// Note: The 'alphaMatte' input is of type image4 rather
-
// than image1 for maximum compatibilty with Flash.
-
-
pixel4 sampSource = sampleNearest(source, outCoord());
-
pixel4 sampAlphaMatte = sampleNearest(alphaMatte, outCoord());
-
pixel1 alphaMatte = (sampAlphaMatte.r + sampAlphaMatte.g + sampAlphaMatte.b) / 3.0;
-
-
result = sampSource * alphaMatte;
-
}
-
}
You can use this kernel in Flash as a fill, filter, or blend mode. In my previous posts, I have demonstrated the use of shaders as fills and filters, so this time around I will use one as a blend mode. Building off of the examples earlier in this post, I modified the previous example to use a shader representing the 'AlphaMattaComposite' byte code as it's blend mode. The one gotcha in this example is that you must enable runtime bitmap caching for the container object (the one that contains the background and foreground objects). Failure to do so will result in the background object's color values being pre-multiplied; as a result, the pixels will be black rather than transparent.
-
// Create a container for storing the background
-
// and foreground objects.
-
//
-
// Note: Runtime bitmap caching must be enabled for
-
// the container in order to avoid alpha being
-
// pre-multiplied when the shader is applied to
-
// it's child objects.
-
-
var container:Sprite = new Sprite();
-
container.cacheAsBitmap = true;
-
addChild(container);
-
-
// Create a 300 x 300 box with a color fill.
-
-
var containerBackground:Sprite = new Sprite();
-
containerBackground.graphics.beginFill(0x008822, 1);
-
containerBackground.graphics.drawRect(0, 0, 300, 300);
-
containerBackground.graphics.endFill();
-
container.addChildAt(containerBackground, 0);
-
-
// Create a matrix for defining the gradient region.
-
-
var gradientMatrix:Matrix = new Matrix();
-
gradientMatrix.createGradientBox(300, 300, 0, 0, 0);
-
-
// Create a 300 x 300 box with a gradient fill.
-
-
var containerForeground:Sprite = new Sprite();
-
containerForeground.graphics.beginGradientFill(GradientType.LINEAR, [0xFFFFFF, 0x000000], [1, 1], [0, 255], gradientMatrix);
-
containerForeground.graphics.drawRect(0, 0, 300, 300);
-
containerForeground.graphics.endFill();
-
container.addChildAt(containerForeground, 1);
-
-
// Create a new shader for represnting the 'AlphaMatteComposite' byte code.
-
-
var shader:Shader = new Shader(new AlphaMatteComposite());
-
-
// Apply the shader to the foreground object. By doing this, the foreground
-
// object will automatically be used as the source input and the background
-
// object will automatically be used as the alphaMatte input.
-
-
containerForeground.blendShader = shader;
Here is an example of a source image, alpha matte, and the resulting composite.
Background:

Source image:

Alpha matte:

Final composite:

Also available on Adobe Labs.
1 commentFP10: Pixel Bender HSLFilter
Sometimes it is useful to adjust colors in the HSL (hue, saturation, lightness) color space rather than RGB color space. There is no convenient way to do this in Flash using ActionScript, though a handful of people including myself have created a ColorMatrix class in the past for handling this task. A Pixel Bender kernel is ideal for this type of manipulation, so I went ahead and created a filter specifically for performing HSL transformations.
The process is as follows:
1.) Sample a pixel's color value and convert it from RGB space to HSL space.
2.) Adjust the HSL values by the amount specified by the hue, saturation, and lightness parameters.
3.) Convert the HSL color back to RGB space.
4.) Apply the resulting RGB color value to the pixel.
As I mentioned in my DisplacementMapFilter post, you can apply this filter in Flash as a shader fill or shader filter; the ideal way being to create a HSLFilter class for interfacing with the shader. I'll probably update this post in the near future with an example of what I am talking about.
Here is the HSLFilter source:
-
// *****************************************************************************************
-
// HSLFilter.pbk
-
//
-
// Copyright (c) 2008 Ryan Taylor | http://www.boostworthy.com
-
//
-
// Permission is hereby granted, free of charge, to any person
-
// obtaining a copy of this software and associated documentation
-
// files (the "Software"), to deal in the Software without
-
// restriction, including without limitation the rights to use,
-
// copy, modify, merge, publish, distribute, sublicense, and/or sell
-
// copies of the Software, and to permit persons to whom the
-
// Software is furnished to do so, subject to the following
-
// conditions:
-
//
-
// The above copyright notice and this permission notice shall be
-
// included in all copies or substantial portions of the Software.
-
//
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-
// OTHER DEALINGS IN THE SOFTWARE.
-
// *****************************************************************************************
-
//
-
// + + + + + + + + +
-
//
-
// *****************************************************************************************
-
-
<languageVersion : 1.0;>
-
-
kernel HSLFilter
-
<
-
namespace : "Boostworthy::Filters";
-
vendor : "Ryan Taylor";
-
version : 1;
-
description : "Basic filter for adjusting the hue, saturation, and lightness of an image.";
-
>
-
{
-
parameter float hue
-
<
-
minValue : -180.0;
-
maxValue : 180.0;
-
defaultValue : 0.0;
-
>;
-
-
parameter float saturation
-
<
-
minValue : -100.0;
-
maxValue : 100.0;
-
defaultValue : 0.0;
-
>;
-
-
parameter float lightness
-
<
-
minValue : -100.0;
-
maxValue : 100.0;
-
defaultValue : 0.0;
-
>;
-
-
input image4 source;
-
output pixel4 result;
-
-
void evaluatePixel()
-
{
-
// Convert sampled pixel from RGB space to HSL space.
-
-
pixel4 samp;
-
float sampMin;
-
float sampMax;
-
float sampDiff;
-
float sampSum;
-
float sampH;
-
float sampS;
-
float sampL;
-
-
samp = sampleNearest(source, outCoord());
-
sampMin = min(samp.r, samp.g);
-
sampMin = min(sampMin, samp.b);
-
sampMax = max(samp.r, samp.g);
-
sampMax = max(sampMax, samp.b);
-
sampDiff = sampMax - sampMin;
-
sampSum = sampMax + sampMin;
-
sampL = sampSum * 0.5;
-
-
if(sampMin == sampMax)
-
sampH = 0.0;
-
else if(sampMax == samp.r)
-
sampH = mod(60.0 * ((samp.g - samp.b) / sampDiff), 360.0);
-
else if(sampMax == samp.g)
-
sampH = 60.0 * ((samp.b - samp.r) / sampDiff) + 120.0;
-
else if(sampMax == samp.b)
-
sampH = 60.0 * ((samp.r - samp.g) / sampDiff) + 240.0;
-
else
-
sampH = 0.0;
-
-
if(sampMin == sampMax)
-
sampS = 0.0;
-
else if(sampL > 0.5)
-
sampS = sampDiff / (2.0 - sampSum);
-
else
-
sampS = sampDiff / sampSum;
-
-
// Transform the sampled HSL values by the amounts specified
-
// by the hue, saturation, and lightness parameters.
-
-
float outH;
-
float outS;
-
float outL;
-
-
outH = sampH - hue;
-
outS = sampS * (saturation / 100.0 + 1.0);
-
outL = sampL - (1.0 - (lightness / 100.0 + 1.0));
-
-
// Convert the transformed HSL values back to RGB space.
-
-
float q;
-
float p;
-
float h;
-
-
if(outL < 0.5)
-
q = outL * (1.0 + outS);
-
else
-
q = outL + outS - outL * outS;
-
-
p = 2.0 * outL - q;
-
h = outH / 360.0;
-
-
float oneOverThree = 1.0 / 3.0;
-
float twoOverThree = 2.0 / 3.0;
-
float oneOverSix = 1.0 / 6.0;
-
float3 t = float3(h + oneOverThree, h, h - oneOverThree);
-
-
if(t.r < 0.0)
-
t.r += 1.0;
-
else if(t.r > 1.0)
-
t.r -= 1.0;
-
-
if(t.g < 0.0)
-
t.g += 1.0;
-
else if(t.g > 1.0)
-
t.g -= 1.0;
-
-
if(t.b < 0.0)
-
t.b += 1.0;
-
else if(t.b > 1.0)
-
t.b -= 1.0;
-
-
pixel4 c = pixel4(0.0, 0.0, 0.0, samp.a);
-
-
if(t.r < oneOverSix)
-
c.r = p + (q - p) * 6.0 * t.r;
-
else if(t.r >= oneOverSix && t.r < 0.5)
-
c.r = q;
-
else if(t.r >= 0.5 && t.r < twoOverThree)
-
c.r = p + (q - p) * 6.0 * (twoOverThree - t.r);
-
else
-
c.r = p;
-
-
if(t.g < oneOverSix)
-
c.g = p + (q - p) * 6.0 * t.g;
-
else if(t.g >= oneOverSix && t.g < 0.5)
-
c.g = q;
-
else if(t.g >= 0.5 && t.g < twoOverThree)
-
c.g = p + (q - p) * 6.0 * (twoOverThree - t.g);
-
else
-
c.g = p;
-
-
if(t.b < oneOverSix)
-
c.b = p + (q - p) * 6.0 * t.b;
-
else if(t.b >= oneOverSix && t.b < 0.5)
-
c.b = q;
-
else if(t.b >= 0.5 && t.b < twoOverThree)
-
c.b = p + (q - p) * 6.0 * (twoOverThree - t.b);
-
else
-
c.b = p;
-
-
// Apply the final ARGB color to the pixel.
-
-
result = c;
-
}
-
}
Last, but not least, here are some examples of the filter applied to an image.
Image with hue 0, saturation 0, and lightness 0:

Image with hue 43, saturation -16, and lightness -44:

Image with hue -118, saturation -14, and lightness 24:

Also available on Adobe Labs.
2 commentsFP10: Pixel Bender DisplacementMapFilter
The Flash API already includes a filter for displacement maps; however I created my own Pixel Bender equivalent for the sake of testing and experimentation. Below is the source, followed by a few examples of how it can be implemented in Flash.
-
// *****************************************************************************************
-
// DisplacementMapFilter.pbk
-
//
-
// Copyright (c) 2008 Ryan Taylor | http://www.boostworthy.com
-
//
-
// Permission is hereby granted, free of charge, to any person
-
// obtaining a copy of this software and associated documentation
-
// files (the "Software"), to deal in the Software without
-
// restriction, including without limitation the rights to use,
-
// copy, modify, merge, publish, distribute, sublicense, and/or sell
-
// copies of the Software, and to permit persons to whom the
-
// Software is furnished to do so, subject to the following
-
// conditions:
-
//
-
// The above copyright notice and this permission notice shall be
-
// included in all copies or substantial portions of the Software.
-
//
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-
// OTHER DEALINGS IN THE SOFTWARE.
-
// *****************************************************************************************
-
//
-
// + + + + + + + + +
-
//
-
// *****************************************************************************************
-
-
<languageVersion : 1.0;>
-
-
kernel DisplacementMapFilter
-
<
-
namespace : "Boostworthy::Filters";
-
vendor : "Ryan Taylor";
-
version : 1;
-
description : "Standard filter for displacing source pixels based on map color values.";
-
>
-
{
-
parameter int2 component
-
<
-
minValue : int2(0, 0);
-
maxValue : int2(3, 3);
-
defaultValue : int2(1, 2);
-
>;
-
-
parameter float2 offset
-
<
-
minValue : float2(-256.0, -256.0);
-
maxValue : float2(256.0, 256.0);
-
defaultValue : float2(0.0, 0.0);
-
>;
-
-
parameter float scale
-
<
-
minValue : -1.0;
-
maxValue : 1.0;
-
defaultValue : 1.0;
-
>;
-
-
input image4 source;
-
input image4 map;
-
output pixel4 result;
-
-
void evaluatePixel()
-
{
-
float2 coord = outCoord();
-
pixel4 mapPixel = sampleLinear(map, coord);
-
-
// Note: The following statements are used for the sake of
-
// Flash compatibility. mapPixel[component[0]], for instance,
-
// is not allowed because the index must be a constant.
-
-
float componentX;
-
-
if(component[0] == 0)
-
componentX = mapPixel[0];
-
else if(component[0] == 1)
-
componentX = mapPixel[1];
-
else if(component[0] == 2)
-
componentX = mapPixel[2];
-
else if(component[0] == 3)
-
componentX = mapPixel[3];
-
-
float componentY;
-
-
if(component[1] == 0)
-
componentY = mapPixel[0];
-
else if(component[1] == 1)
-
componentY = mapPixel[1];
-
else if(component[1] == 2)
-
componentY = mapPixel[2];
-
else if(component[1] == 3)
-
componentY = mapPixel[3];
-
-
float x = coord.x + (componentX - 0.5) * offset[0] * scale;
-
float y = coord.y + (componentY - 0.5) * offset[1] * scale;
-
-
result = sampleLinear(source, float2(x, y));
-
}
-
}
NOTE: It is important to make sure that the main source image is the first input. Flash's ShaderFilter class makes this assumption and automatically passes it's input to the input at index 0.
In Flash, you can embed the 'DisplacementMapFilter.pbj' file at compiletime or keep it external and load it at runtime using a Loader instance. Regardless of the approach, you then feed the filter's byte code to a Shader object as seen below.
-
var sourceImage:Bitmap = Bitmap(new SourceImage());
-
var mapImage:Bitmap = Bitmap(new MapImage());
-
-
var shader:Shader = new Shader(new DisplacementMapFilter());
-
shader.data.source.input = sourceImage.bitmapData;
-
shader.data.map.input = mapImage.bitmapData;
-
shader.data.component.value = [1, 2];
-
shader.data.offset.value = [50, 190];
-
shader.data.scale.value = [1];
Once you have set the inputs and tweaked any parameters, one way to render the shader is to draw it as a fill using the Flash drawing API.
-
var container:Sprite = new Sprite();
-
container.graphics.beginShaderFill(shader);
-
container.graphics.drawRect(0, 0, sourceImage.width, sourceImage.height);
-
container.graphics.endFill();
-
addChild(container);
Alternatively, you can also create a ShaderFilter and apply it to a BitmapData object.
-
var containerData:BitmapData = new BitmapData(sourceImage.width, sourceImage.height);
-
var container:Bitmap = new Bitmap(containerData);
-
-
var displacementMapFilter:ShaderFilter = new ShaderFilter(shader);
-
var filterRect:Rectangle = new Rectangle(0, 0, sourceImage.width, sourceImage.height);
-
var filterPoint:Point = new Point(0, 0);
-
-
containerData.applyFilter(sourceImage.bitmapData, filterRect, filterPoint, displacementMapFilter);
-
-
addChild(container);
Unlike the other filter classes, the ShaderFilter class is not final - you can create subclasses for interfacing with your custom Pixel Bender filters. Performance-wise, the fill approach seems to beat out the use of a filter slightly, though that may change by the final release of Flash Player 10 as they continue to optimize things.
In terms of usage, the filter accepts two image inputs; one for a source image and one for the displacement map. The map's colors dictate the displacement of the pixels. By default, the component used for X is the green channel and for Y the blue channel. A channel value of 128 translates to 0 movement along the corresponding component's axis, where as 0 is -1, 255 is 1, and everything in between is smooth steps. This value is then multiplied against an offset and scale value before being applied as the final displacement. Here is an example:
Source image:

Map image:

Source image with displacement applied {component:[1, 2], offset:[50, 190], scale:[1]}:

Map image overlaid 50% over displaced source image:

Also available on Adobe Labs.
6 comments