blob: 67f8fb67d86bc7af77666f488dea6aa70444723e [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package spark.effects
{
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.utils.ByteArray;
import mx.core.IUIComponent;
import mx.core.mx_internal;
import mx.effects.IEffectInstance;
import mx.resources.IResourceManager;
import mx.resources.ResourceManager;
import spark.effects.supportClasses.AnimateTransitionShaderInstance;
import spark.primitives.supportClasses.GraphicElement;
import spark.utils.BitmapUtil;
use namespace mx_internal;
//--------------------------------------
// Other metadata
//--------------------------------------
/**
* The AnimateTransitionShader effect uses Pixel Bender,
* which is not supported for AIR mobile applications.
*/
[DiscouragedForProfile("mobileDevice")]
[ResourceBundle("sparkEffects")]
/**
* The AnimateTransitionShader effect animates a transition between two bitmaps,
* one representing the start state (<code>bitmapFrom</code>), and
* the other representing the end state (<code>bitmapTo</code>).
*
* <p>The animation is performed by running a pixel-shader program,
* specified by the <code>shader</code> property,
* using the two bitmaps as input.
* The bitmaps are represented by an instance of the flash.display.BitmapData class.
* You can create your own pixel-shader program
* by using Adobe Pixel Bender Toolkit.</p>
*
* <p>If either bitmap is
* not supplied, that value is determined dynamically from
* either the appropriate state of the target in a transition or,
* if the effect is not running in a transition, from the
* target directly. If
* the effect is run in a transition and the target object either
* goes away or comes into existence during that state change,
* then a fully-transparent bitmap is used to represent
* that object when it does not exist.</p>
*
* <p>This effect can only be run on targets that are either
* UIComponents or GraphicElements, since capturing the bitmap
* of the object requires information about the object that only
* exists in these classes.</p>
*
* <p>Because the effect is bitmap-based, and the underlying
* pixel-shader program expects both bitmaps to be the same size,
* the effect only works correctly when both bitmaps are
* of the same size. This means that if the target object changes
* size or changes orientation leading to a different size bounding
* box, then the effect might not play correctly.</p>
*
* <p>This effect and its subclasses differ from other effects in
* Flex in that they are intended to work on their own, and may
* not have the intended result when run in parallel with other effects.
* This constraint comes from the fact that both of the before and after
* bitmaps are captured before the start of the effect. So if something
* happens to the target object after these bitmaps are calculated,
* such as another effect changing the target's properties, then those
* changes are not be accounted for in the pre-calculated bitmap and
* the results might not be as expected. To ensure correct playing of
* these bitmap-based effects, they should be played alone on
* their target objects.</p>
*
* @mxml
*
* <p>The <code>&lt;s:AnimateTransitionShader&gt;</code> tag
* inherits all of the tag attributes of its superclass,
* and adds the following tag attributes:</p>
*
* <pre>
* &lt;s:AnimateTransitionShader
* <b>Properties</b>
* id="ID"
* bitmapFrom="no default"
* bitmapTo="no default"
* shaderByteCode="no default"
* sahderProperties="no default"
* /&gt;
* </pre>
*
* @see flash.display.BitmapData
* @see spark.effects.supportClasses.AnimateTransitionShaderInstance
* @see spark.primitives.supportClasses.GraphicElement
*
* @includeExample examples/AnimateTransitionShaderExample.mxml
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public class AnimateTransitionShader extends Animate
{
/**
* Constructor.
*
* @param target The Object to animate with this effect.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function AnimateTransitionShader(target:Object=null)
{
super(target);
instanceClass = AnimateTransitionShaderInstance;
}
//--------------------------------------------------------------------------
//
// Class variables
//
//--------------------------------------------------------------------------
/**
* @private
* Storage for the resourceManager getter.
* This gets initialized on first access,
* not at static initialization time, in order to ensure
* that the Singleton registry has already been initialized.
*/
private static var _resourceManager:IResourceManager;
/**
* @private
* A reference to the object which manages
* all of the application's localized resources.
* This is a singleton instance which implements
* the IResourceManager interface.
*/
private static function get resourceManager():IResourceManager
{
if (!_resourceManager)
_resourceManager = ResourceManager.getInstance();
return _resourceManager;
}
/**
* The bitmap data representing the start state of this effect.
* If this property is not set, it is calculated automatically
* when the effect is played by taking a snapshot of the target
* object, or by using a transparent bitmap if the object does not
* exist in the start view state of a transition.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var bitmapFrom:BitmapData;
/**
* The bitmap data representing the end state of this effect.
* If this property is not set, it is calculated automatically
* when the effect is played by taking a snapshot of the target
* object, or by using a transparent bitmap if the object does not
* exist in the end view state of a transition.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var bitmapTo:BitmapData;
/**
* The bytecode for the pixel-shader program that the effect uses
* to animate between the two bitmaps. This
* property can be represented as either a ByteArray or as a
* Class representing a ByteArray (which is what results
* when you embed a resource).
*
* <p>The pixel-shader program can have arbitrary functionality and inputs, but
* must, at a minimum, have three <code>image4</code> inputs.
* The first input, which can be named anything, should go
* unused by your pixel-shader program code - it exists only to satisfy the
* Flash requirement of assigning a filtered object to the
* first input. Note that inputs that go completely unused in a
* pixel-shader program might be optimized out, so your code should
* at least reference this input once.</p>
*
* <p>There must be at least two other input bitmaps
* named <code>from</code> and <code>to</code>
* which represent the before and after bitmap images.
* Finally, you must define one
* <code>float</code> parameter named <code>progress</code>
* that contains the elapsed fraction of the effect.</p>
*
* <p>You can specify two optional parameters, <code>width</code>
* and <code>height</code>. If they exist, they
* are automatically set to the width and height of the
* effect target.</p>
*
* <p>See the Pixel Bender Toolkit documentation for more
* information on writing pixel-shader programs for Flash.
* You can also look at the source code for the CrossFade.pbk file in the
* frameworks\projects\flex4\src\spark\effects directory of the Flex source code.</p>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var shaderByteCode:Object;
/**
* A map of parameter name/value pairs passed to the pixel-shader program
* before playing. For example,
* to set a parameter named <code>direction</code> in a
* shader with a Pixel Bender pbj file in Wipe.pbj, the calling
* code could do the following:
*
* <pre>
* [Embed(source="Wipe.pbj", mimeType="application/octet-stream")]
* private var WipeCodeClass:Class;
* var shaderEffect = new AnimateTransitionShader();
* shaderEffect.shaderByteCode = WipeCodeClass;
* shaderEffect.shaderProperties = {direction : 1};
* </pre>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var shaderProperties:Object;
/**
* @private
*/
override public function getAffectedProperties():Array /* of String */
{
// We track visible and parent so that we can automatically
// perform transitions from/to states where the target either
// does not exist or is not visible
// Note that 'bitmapInfo' is an Object map containing both a bitmap
// and the visual bounds of that bitmap on the screen
return ["bitmapInfo", "visible", "parent"];
}
/**
* @private
*/
override protected function getValueFromTarget(target:Object, property:String):*
{
if (property != "bitmapInfo")
return super.getValueFromTarget(target, property);
// Return a null bitmap for non-visible targets
if (!target.visible || !target.parent)
return null;
if (!(target is GraphicElement || target is IUIComponent))
throw new Error(resourceManager.getString("sparkEffects", "cannotOperateOn"));
var bmData:BitmapData;
var tempFilters:Array = target.filters;
var bounds:Rectangle;
target.filters = [];
try
{
if (target is GraphicElement)
{
bmData = GraphicElement(target).captureBitmapData(true, 0, false);
// The GraphicElement version does not calculate the visual bounds,
// so just create dummy bounds with the correct width/height
bounds = new Rectangle(0, 0, bmData ? bmData.width : 0, bmData ? bmData.height : 0);
}
else
{
// Passing in a non-null bounds parameter forces getSnapshot()
// to return the visual bounds of the object
bounds = new Rectangle();
bmData = BitmapUtil.getSnapshot(IUIComponent(target), bounds, true);
}
}
catch (e:SecurityError)
{
// Do nothing and let it return null.
}
// The effect instance will retrieve the bitmap and bounds from the object
// stored here
var bmHolder:Object = {bitmap:bmData, bounds:bounds};
target.filters = tempFilters;
return bmHolder;
}
/**
* @private
*/
override protected function initInstance(instance:IEffectInstance):void
{
super.initInstance(instance);
var animateTransitionShaderInstance:AnimateTransitionShaderInstance =
AnimateTransitionShaderInstance(instance);
animateTransitionShaderInstance.bitmapFrom = bitmapFrom;
animateTransitionShaderInstance.bitmapTo = bitmapTo;
if (!shaderByteCode)
// User should always supply a shader, but if they don't just
// pass it on
animateTransitionShaderInstance.shaderByteCode = null;
else
animateTransitionShaderInstance.shaderByteCode =
(shaderByteCode is ByteArray) ?
ByteArray(shaderByteCode) :
new shaderByteCode();
animateTransitionShaderInstance.shaderProperties = shaderProperties;
}
}
}