1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2008 Adobe Systems Incorporated
5//  All Rights Reserved.
6//
7//  NOTICE: Adobe permits you to use, modify, and distribute this file
8//  in accordance with the terms of the license agreement accompanying it.
9//
10////////////////////////////////////////////////////////////////////////////////
11package spark.effects
12{
13import flash.display.BitmapData;
14import flash.geom.Rectangle;
15import flash.utils.ByteArray;
16
17import mx.core.IUIComponent;
18import mx.core.mx_internal;
19import mx.effects.IEffectInstance;
20import mx.resources.IResourceManager;
21import mx.resources.ResourceManager;
22
23import spark.effects.supportClasses.AnimateTransitionShaderInstance;
24import spark.primitives.supportClasses.GraphicElement;
25import spark.utils.BitmapUtil;
26
27use namespace mx_internal;
28
29//--------------------------------------
30//  Other metadata
31//--------------------------------------
32
33/**
34 *  The AnimateTransitionShader effect uses Pixel Bender,
35 *  which is not supported for AIR mobile applications.
36 */
37[DiscouragedForProfile("mobileDevice")]
38
39[ResourceBundle("sparkEffects")]
40
41/**
42 * The AnimateTransitionShader effect animates a transition between two bitmaps,
43 * one representing the start state (<code>bitmapFrom</code>), and
44 * the other representing the end state (<code>bitmapTo</code>).
45 *
46 * <p>The animation is performed by running a pixel-shader program,
47 * specified by the <code>shader</code> property,
48 * using the two bitmaps as input.
49 * The bitmaps are represented by an instance of the flash.display.BitmapData class.
50 * You can create your own pixel-shader program
51 * by using Adobe Pixel Bender Toolkit.</p>
52 *
53 * <p>If either bitmap is
54 * not supplied, that value is determined dynamically from
55 * either the appropriate state of the target in a transition or,
56 * if the effect is not running in a transition, from the
57 * target directly. If
58 * the effect is run in a transition and the target object either
59 * goes away or comes into existence during that state change,
60 * then a fully-transparent bitmap is used to represent
61 * that object when it does not exist.</p>
62 *
63 * <p>This effect can only be run on targets that are either
64 * UIComponents or GraphicElements, since capturing the bitmap
65 * of the object requires information about the object that only
66 * exists in these classes.</p>
67 *
68 * <p>Because the effect is bitmap-based, and the underlying
69 * pixel-shader program expects both bitmaps to be the same size,
70 * the effect only works correctly when both bitmaps are
71 * of the same size. This means that if the target object changes
72 * size or changes orientation leading to a different size bounding
73 * box, then the effect might not play correctly.</p>
74 *
75 * <p>This effect and its subclasses differ from other effects in
76 * Flex in that they are intended to work on their own, and may
77 * not have the intended result when run in parallel with other effects.
78 * This constraint comes from the fact that both of the before and after
79 * bitmaps are captured before the start of the effect. So if something
80 * happens to the target object after these bitmaps are calculated,
81 * such as another effect changing the target's properties, then those
82 * changes are not be accounted for in the pre-calculated bitmap and
83 * the results might not be as expected. To ensure correct playing of
84 * these bitmap-based effects, they should be played alone on
85 * their target objects.</p>
86 *
87 *  @mxml
88 *
89 *  <p>The <code>&lt;s:AnimateTransitionShader&gt;</code> tag
90 *  inherits all of the tag attributes of its superclass,
91 *  and adds the following tag attributes:</p>
92 *
93 *  <pre>
94 *  &lt;s:AnimateTransitionShader
95 *    <b>Properties</b>
96 *    id="ID"
97 *    bitmapFrom="no default"
98 *    bitmapTo="no default"
99 *    shaderByteCode="no default"
100 *    sahderProperties="no default"
101 *  /&gt;
102 *  </pre>
103 *
104 *  @see flash.display.BitmapData
105 *  @see spark.effects.supportClasses.AnimateTransitionShaderInstance
106 *  @see spark.primitives.supportClasses.GraphicElement
107 *
108 *  @includeExample examples/AnimateTransitionShaderExample.mxml
109 *
110 *  @langversion 3.0
111 *  @playerversion Flash 10
112 *  @playerversion AIR 1.5
113 *  @productversion Flex 4
114 */
115public class AnimateTransitionShader extends Animate
116{
117
118    /**
119     *  Constructor.
120     *
121     *  @param target The Object to animate with this effect.
122     *
123     *  @langversion 3.0
124     *  @playerversion Flash 10
125     *  @playerversion AIR 1.5
126     *  @productversion Flex 4
127     */
128     public function AnimateTransitionShader(target:Object=null)
129    {
130        super(target);
131
132        instanceClass = AnimateTransitionShaderInstance;
133    }
134
135
136    //--------------------------------------------------------------------------
137    //
138    //  Class variables
139    //
140    //--------------------------------------------------------------------------
141
142    /**
143     *  @private
144     *  Storage for the resourceManager getter.
145     *  This gets initialized on first access,
146     *  not at static initialization time, in order to ensure
147     *  that the Singleton registry has already been initialized.
148     */
149    private static var _resourceManager:IResourceManager;
150
151    /**
152     *  @private
153     *  A reference to the object which manages
154     *  all of the application's localized resources.
155     *  This is a singleton instance which implements
156     *  the IResourceManager interface.
157     */
158    private static function get resourceManager():IResourceManager
159    {
160        if (!_resourceManager)
161            _resourceManager = ResourceManager.getInstance();
162
163        return _resourceManager;
164    }
165
166    /**
167     * The bitmap data representing the start state of this effect.
168     * If this property is not set, it is calculated automatically
169     * when the effect is played by taking a snapshot of the target
170     * object, or by using a transparent bitmap if the object does not
171     * exist in the start view state of a transition.
172     *
173     *  @langversion 3.0
174     *  @playerversion Flash 10
175     *  @playerversion AIR 1.5
176     *  @productversion Flex 4
177     */
178    public var bitmapFrom:BitmapData;
179
180    /**
181     * The bitmap data representing the end state of this effect.
182     * If this property is not set, it is calculated automatically
183     * when the effect is played by taking a snapshot of the target
184     * object, or by using a transparent bitmap if the object does not
185     * exist in the end view state of a transition.
186     *
187     *  @langversion 3.0
188     *  @playerversion Flash 10
189     *  @playerversion AIR 1.5
190     *  @productversion Flex 4
191     */
192    public var bitmapTo:BitmapData;
193
194    /**
195     * The bytecode for the pixel-shader program that the effect uses
196     * to animate between the two bitmaps. This
197     * property can be represented as either a ByteArray or as a
198     * Class representing a ByteArray (which is what results
199     * when you embed a resource).
200     *
201     * <p>The pixel-shader program can have arbitrary functionality and inputs, but
202     * must, at a minimum, have three <code>image4</code> inputs.
203     * The first input, which can be named anything, should go
204     * unused by your pixel-shader program  code - it exists only to satisfy the
205     * Flash requirement of assigning a filtered object to the
206     * first input. Note that inputs that go completely unused in a
207     * pixel-shader program might be optimized out, so your code should
208     * at least reference this input once.</p>
209     *
210     * <p>There must be at least two other input bitmaps
211     * named <code>from</code> and <code>to</code>
212     * which represent the before and after bitmap images.
213     * Finally, you must define one
214     * <code>float</code> parameter named <code>progress</code>
215     * that contains the elapsed fraction of the effect.</p>
216     *
217     * <p>You can specify two optional parameters, <code>width</code>
218     * and <code>height</code>. If they exist, they
219     * are automatically set to the width and height of the
220     * effect target.</p>
221     *
222     * <p>See the Pixel Bender Toolkit documentation for more
223     * information on writing pixel-shader programs for Flash.
224     * You can also look at the source code for the CrossFade.pbk file in the
225     * frameworks\projects\flex4\src\spark\effects directory of the Flex source code.</p>
226     *
227     *  @langversion 3.0
228     *  @playerversion Flash 10
229     *  @playerversion AIR 1.5
230     *  @productversion Flex 4
231     */
232    public var shaderByteCode:Object;
233
234    /**
235     * A map of parameter name/value pairs passed to the pixel-shader program
236     * before playing. For example,
237     * to set a parameter named <code>direction</code> in a
238     * shader with a Pixel Bender pbj file in Wipe.pbj, the calling
239     * code could do the following:
240     *
241     * <pre>
242     *   [Embed(source="Wipe.pbj", mimeType="application/octet-stream")]
243     *   private var WipeCodeClass:Class;
244     *   var shaderEffect = new AnimateTransitionShader();
245     *   shaderEffect.shaderByteCode = WipeCodeClass;
246     *   shaderEffect.shaderProperties = {direction : 1};
247     * </pre>
248     *
249     *  @langversion 3.0
250     *  @playerversion Flash 10
251     *  @playerversion AIR 1.5
252     *  @productversion Flex 4
253     */
254    public var shaderProperties:Object;
255
256    /**
257     *  @private
258     */
259    override public function getAffectedProperties():Array /* of String */
260    {
261        // We track visible and parent so that we can automatically
262        // perform transitions from/to states where the target either
263        // does not exist or is not visible
264        // Note that 'bitmapInfo' is an Object map containing both a bitmap
265        // and the visual bounds of that bitmap on the screen
266        return ["bitmapInfo", "visible", "parent"];
267    }
268
269    /**
270     *  @private
271     */
272    override protected function getValueFromTarget(target:Object, property:String):*
273    {
274        if (property != "bitmapInfo")
275            return super.getValueFromTarget(target, property);
276
277        // Return a null bitmap for non-visible targets
278        if (!target.visible || !target.parent)
279            return null;
280
281        if (!(target is GraphicElement || target is IUIComponent))
282            throw new Error(resourceManager.getString("sparkEffects", "cannotOperateOn"));
283        var bmData:BitmapData;
284        var tempFilters:Array = target.filters;
285        var bounds:Rectangle;
286        target.filters = [];
287
288        try
289        {
290            if (target is GraphicElement)
291            {
292                bmData = GraphicElement(target).captureBitmapData(true, 0, false);
293                // The GraphicElement version does not calculate the visual bounds,
294                // so just create dummy bounds with the correct width/height
295                bounds = new Rectangle(0, 0, bmData ? bmData.width : 0, bmData ? bmData.height : 0);
296            }
297            else
298            {
299                // Passing in a non-null bounds parameter forces getSnapshot()
300                // to return the visual bounds of the object
301                bounds = new Rectangle();
302                bmData = BitmapUtil.getSnapshot(IUIComponent(target), bounds, true);
303            }
304        }
305        catch (e:SecurityError)
306        {
307            // Do nothing and let it return null.
308        }
309        // The effect instance will retrieve the bitmap and bounds from the object
310        // stored here
311        var bmHolder:Object = new Object();
312        bmHolder["bitmap"] = bmData;
313        bmHolder["bounds"] = bounds;
314
315        target.filters = tempFilters;
316
317        return bmHolder;
318    }
319
320    /**
321     *  @private
322     */
323    override protected function initInstance(instance:IEffectInstance):void
324    {
325        super.initInstance(instance);
326
327        var animateTransitionShaderInstance:AnimateTransitionShaderInstance =
328            AnimateTransitionShaderInstance(instance);
329
330        animateTransitionShaderInstance.bitmapFrom = bitmapFrom;
331        animateTransitionShaderInstance.bitmapTo = bitmapTo;
332
333        if (!shaderByteCode)
334            // User should always supply a shader, but if they don't just
335            // pass it on
336            animateTransitionShaderInstance.shaderByteCode = null;
337        else
338            animateTransitionShaderInstance.shaderByteCode =
339                (shaderByteCode is ByteArray) ?
340                ByteArray(shaderByteCode) :
341                new shaderByteCode();
342        animateTransitionShaderInstance.shaderProperties = shaderProperties;
343    }
344}
345}
346