/**
* VERSION: 0.95
* DATE: 9/22/2009
* AS3
* UPDATES AND DOCUMENTATION AT: http://blog.greensock.com/
**/
package com.greensock {
import flash.display.*;
import flash.events.Event;
import flash.geom.*;
import flash.utils.*;
/**
* TweenProxy3D essentially "stands in" for a DisplayObject, so you set the various properties of
* the TweenProxy3D and in turn, it handles setting the corresponding properties of the DisplayObject
* which it controls, adding three important capabilities:
*
registration
point is based on the DisplayObject's parent's coordinate space whereas the localRegistration
corresponds
* to the DisplayObject's inner coordinates, so it's very simple to define the registration point whichever way you prefer.
*
* var myProxy:TweenProxy3D = TweenProxy3D.create(mySprite);
* myProxy.registration = new Vector3D(100, 100, 100); //sets a custom registration point at x:100, y:100, and z:100
* myProxy.rotationY = 30; //sets mySprite.rotationY to 30, rotating around the custom registration point
* myProxy.skewX = 45;
* TweenLite.to(myProxy, 3, {rotationX:50}); //tweens the rotationX around the custom registration point.
*
*
* PROPERTIES ADDED WITH TweenProxy3D:
*
* import com.greensock.TweenProxy3D;
* import com.greensock.TweenLite;
* import com.greensock.easing.Elastic;
* import flash.geom.Vector3D;
*
* var myProxy:TweenProxy3D = TweenProxy3D.create(my_mc);
* myProxy.registration = new Vector3D(100, 100, 100);
* TweenLite.to(myProxy, 3, {skewX:30, scale:0.5, ease:Elastic.easeOut});
*
* Copyright 2010, GreenSock. All rights reserved. This work is subject to the terms in http://www.greensock.com/terms_of_use.html or for corporate Club GreenSock members, the software agreement that was issued with the corporate membership.
*
* @author Jack Doyle, jack@greensock.com
*/
dynamic public class TweenProxy3D extends Proxy {
/** @private **/
public static const VERSION:Number = 0.94;
/** @private **/
private static const _DEG2RAD:Number = Math.PI / 180; //precompute for speed
/** @private **/
private static const _RAD2DEG:Number = 180 / Math.PI; //precompute for speed
/** @private **/
private static var _dict:Dictionary = new Dictionary(false);
/** @private **/
private static var _addedProps:String = " tint tintPercent scale skewX skewY skewX2 skewY2 target registration registrationX registrationY localRegistration localRegistrationX localRegistrationY "; //used in hasProperty
/** @private **/
private var _target:DisplayObject;
/** @private **/
private var _root:DisplayObject;
/** @private **/
private var _scaleX:Number;
/** @private **/
private var _scaleY:Number;
/** @private **/
private var _scaleZ:Number;
/** @private **/
private var _rotationX:Number;
/** @private **/
private var _rotationY:Number;
/** @private **/
private var _rotationZ:Number;
/** @private **/
private var _skewX:Number; //in radians!
/** @private **/
private var _skewY:Number; //in radians!
/** @private **/
private var _skewX2Mode:Boolean;
/** @private **/
private var _skewY2Mode:Boolean;
/** @private **/
private var _proxies:Array; //populated with all TweenProxy3D instances with the same _target (basically a faster way to access _dict[_target])
/** @private **/
private var _localRegistration:Vector3D; //according to the local coordinates of _target (not _target.parent)
/** @private **/
private var _registration:Vector3D; //according to _target.parent coordinates
/** @private **/
private var _regAt0:Boolean; //If the localRegistration point is at 0, 0, this is true. We just use it to speed up processing in getters/setters.
/** @private **/
public var ignoreSiblingUpdates:Boolean = false;
public function TweenProxy3D($target:DisplayObject, $ignoreSiblingUpdates:Boolean=false) {
_target = $target;
if (_dict[_target] == undefined) {
_dict[_target] = [];
}
if (_target.root != null) {
_root = _target.root;
} else {
_target.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage, false, 0, true);
}
_proxies = _dict[_target];
_proxies[_proxies.length] = this;
_localRegistration = new Vector3D();
_registration = new Vector3D();
if (_target.transform.matrix3D == null) {
_target.z = 0;
}
this.ignoreSiblingUpdates = $ignoreSiblingUpdates;
calibrate();
}
public static function create($target:DisplayObject, $allowRecycle:Boolean=true):TweenProxy3D {
if (_dict[$target] != null && $allowRecycle) {
return _dict[$target][0];
} else {
return new TweenProxy3D($target);
}
}
/** @private **/
protected function onAddedToStage($e:Event):void {
_root = _target.root;
_target.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
public function calibrate():void {
_rotationX = _target.rotationX;
_rotationY = _target.rotationY;
_rotationZ = _target.rotationZ;
_target.rotationX = _rotationX; //just forces the skew to be zero.
_skewX = _skewY = 0;
_scaleX = _target.scaleX;
_scaleY = _target.scaleY;
_scaleZ = _target.scaleZ;
calibrateRegistration();
}
public function get target():DisplayObject {
return _target;
}
public function destroy():void {
var a:Array = _dict[_target], i:int;
for (i = a.length - 1; i > -1; i--) {
if (a[i] == this) {
a.splice(i, 1);
}
}
if (a.length == 0) {
delete _dict[_target];
}
_target = null;
_localRegistration = null;
_registration = null;
_proxies = null;
}
//---- PROXY FUNCTIONS ------------------------------------------------------------------------------------------
/** @private **/
flash_proxy override function callProperty($name:*, ...$args:Array):* {
return _target[$name].apply(null, $args);
}
/** @private **/
flash_proxy override function getProperty($prop:*):* {
return _target[$prop];
}
/** @private **/
flash_proxy override function setProperty($prop:*, $value:*):void {
_target[$prop] = $value;
}
/** @private **/
flash_proxy override function hasProperty($name:*):Boolean {
if (_target.hasOwnProperty($name)) {
return true;
} else if (_addedProps.indexOf(" " + $name + " ") != -1) {
return true;
} else {
return false;
}
}
//---- GENERAL REGISTRATION -----------------------------------------------------------------------
/** @private **/
public function moveRegX($n:Number):void {
_registration.x += $n;
}
/** @private **/
public function moveRegY($n:Number):void {
_registration.y += $n;
}
/** @private **/
public function moveRegZ($n:Number):void {
_registration.z += $n;
}
/** @private **/
private function reposition():void {
if (_root != null) {
var v:Vector3D = _target.transform.getRelativeMatrix3D(_root).deltaTransformVector(_localRegistration);
_target.x = _registration.x - v.x;
_target.y = _registration.y - v.y;
_target.z = _registration.z - v.z;
}
}
/** @private **/
private function updateSiblingProxies():void {
for (var i:int = _proxies.length - 1; i > -1; i--) {
if (_proxies[i] != this) {
_proxies[i].onSiblingUpdate(_scaleX, _scaleY, _scaleZ, _rotationX, _rotationY, _rotationZ, _skewX, _skewY);
}
}
}
/** @private **/
private function calibrateLocal():void {
if (_target.parent != null) {
var m:Matrix3D = _target.transform.getRelativeMatrix3D(_target.parent);
m.invert();
var v:Vector3D = m.deltaTransformVector(new Vector3D(_registration.x - _target.x, _registration.y - _target.y, _registration.z - _target.z));
_localRegistration.x = v.x;
_localRegistration.y = v.y;
_localRegistration.z = v.z;
_regAt0 = (_localRegistration.x == 0 && _localRegistration.y == 0 && _localRegistration.z == 0);
}
}
/** @private **/
private function calibrateRegistration():void {
if (_root != null) {
var v:Vector3D = _target.transform.getRelativeMatrix3D(_root).deltaTransformVector(_localRegistration);
_registration.x = _target.x + v.x;
_registration.y = _target.y + v.y;
_registration.z = _target.z + v.z;
}
}
/** @private **/
public function onSiblingUpdate($scaleX:Number, $scaleY:Number, $scaleZ:Number, $rotationX:Number, $rotationY:Number, $rotationZ:Number, $skewX:Number, $skewY:Number):void {
_scaleX = $scaleX;
_scaleY = $scaleY;
_scaleZ = $scaleZ;
_rotationX = $rotationX;
_rotationY = $rotationY;
_rotationZ = $rotationZ;
_skewX = $skewX;
_skewY = $skewY;
if (this.ignoreSiblingUpdates) {
calibrateLocal();
} else {
calibrateRegistration();
}
}
//---- LOCAL REGISTRATION ---------------------------------------------------------------------------
public function get localRegistration():Vector3D {
return _localRegistration;
}
public function set localRegistration($v:Vector3D):void {
_localRegistration = $v;
calibrateRegistration();
}
public function get localRegistrationX():Number {
return _localRegistration.x;
}
public function set localRegistrationX($n:Number):void {
_localRegistration.x = $n;
calibrateRegistration();
}
public function get localRegistrationY():Number {
return _localRegistration.y;
}
public function set localRegistrationY($n:Number):void {
_localRegistration.y = $n;
calibrateRegistration();
}
public function get localRegistrationZ():Number {
return _localRegistration.z;
}
public function set localRegistrationZ($n:Number):void {
_localRegistration.z = $n;
calibrateRegistration();
}
//---- REGISTRATION (OUTER) ----------------------------------------------------------------------
public function get registration():Vector3D {
return _registration
}
public function set registration($v:Vector3D):void {
_registration = $v;
calibrateLocal();
}
public function get registrationX():Number {
return _registration.x;
}
public function set registrationX($n:Number):void {
_registration.x = $n;
calibrateLocal();
}
public function get registrationY():Number {
return _registration.y;
}
public function set registrationY($n:Number):void {
_registration.y = $n;
calibrateLocal();
}
public function get registrationZ():Number {
return _registration.z;
}
public function set registrationZ($n:Number):void {
_registration.z = $n;
calibrateLocal();
}
//---- X/Y MOVEMENT ---------------------------------------------------------------------------------
public function get x():Number {
return _registration.x;
}
public function set x($n:Number):void {
var tx:Number = ($n - _registration.x);
_target.x += tx;
for (var i:int = _proxies.length - 1; i > -1; i--) {
if (_proxies[i] == this || !_proxies[i].ignoreSiblingUpdates) {
_proxies[i].moveRegX(tx);
}
}
}
public function get y():Number {
return _registration.y;
}
public function set y($n:Number):void {
var ty:Number = ($n - _registration.y);
_target.y += ty;
for (var i:int = _proxies.length - 1; i > -1; i--) {
if (_proxies[i] == this || !_proxies[i].ignoreSiblingUpdates) {
_proxies[i].moveRegY(ty);
}
}
}
public function get z():Number {
return _registration.z;
}
public function set z($n:Number):void {
var tz:Number = ($n - _registration.z);
_target.z += tz;
for (var i:int = _proxies.length - 1; i > -1; i--) {
if (_proxies[i] == this || !_proxies[i].ignoreSiblingUpdates) {
_proxies[i].moveRegZ(tz);
}
}
}
//---- ROTATION ----------------------------------------------------------------------------
public function get rotationX():Number {
return _rotationX;
}
public function set rotationX($n:Number):void {
_rotationX = $n;
if (_skewX != 0 || _skewY != 0) {
updateWithSkew();
} else {
_target.rotationX = $n;
if (!_regAt0) {
reposition();
}
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
}
public function get rotationY():Number {
return _rotationY;
}
public function set rotationY($n:Number):void {
_rotationY = $n;
if (_skewX != 0 || _skewY != 0) {
updateWithSkew();
} else {
_target.rotationY = $n;
if (!_regAt0) {
reposition();
}
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
}
public function get rotationZ():Number {
return _rotationZ;
}
public function set rotationZ($n:Number):void {
_rotationZ = $n;
if (_skewX != 0 || _skewY != 0) {
updateWithSkew();
} else {
_target.rotationZ = $n;
if (!_regAt0) {
reposition();
}
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
}
public function get rotation():Number {
return _rotationZ;
}
public function set rotation($n:Number):void {
this.rotationZ = $n;
}
//---- SKEW -------------------------------------------------------------------------------
/** @private **/
private function updateWithSkew():void {
var sm:Matrix3D, v:Vector.