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><s:AnimateTransitionShader></code> tag 90 * inherits all of the tag attributes of its superclass, 91 * and adds the following tag attributes:</p> 92 * 93 * <pre> 94 * <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 * /> 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