In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

[BetweenAS3] flash.geom.Matrix3D Tween

/**
 * Copyright yonatan ( http://wonderfl.net/user/yonatan )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/nhET
 */

// forked from yonatan's [BetweenAS3] Papervision Matrix3D Tween
// forked from nitoyon's [BetweenAS3] Random Text Tween
package {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.ui.Mouse;
    import flash.ui.MouseCursor;
    import org.libspark.betweenas3.easing.*;

    [SWF (backgroundColor="0x000000")]

    public class FlashTest extends Sprite {
        public function FlashTest() {
            Mouse.cursor = MouseCursor.BUTTON;
            x = y = 456/2;

            var s:Sprite = new Sprite;
            s.graphics.beginFill(0x4488ff);
            s.graphics.drawRect(-100, -100, 200, 200);
            s.graphics.endFill();
            s.alpha = 0.8;
            addChild(s);

            var dst:Sprite = new Sprite;
            dst.z = 0; // creates a Matrix3D instance

            var tween:Matrix3DTween = new Matrix3DTween();
            s.z = 0; // creates a Matrix3D instance
            tween.target = s;
            tween.easing = Sine.easeOut;
            tween.matrix = dst.transform.matrix3D;
            tween.time = 1;

            function onClick(e:Event):void {
                dst.x = -100 + 200*Math.random();
                dst.y = -100 + 200*Math.random();
                dst.z = -100 + 200*Math.random();
                dst.scaleX = 2*Math.random();
                dst.scaleY = 2*Math.random();
                dst.scaleZ = 2*Math.random();
                dst.rotationX = 360*Math.random();
                dst.rotationY = 360*Math.random();

                tween.target = s; // reset initial matrix to the current one.
                tween.play();
            }

            stage.addEventListener("click", onClick);
            onClick(null);
        }
    }
}

import flash.display.DisplayObject;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.core.easing.IEasing;
import org.libspark.betweenas3.core.ticker.ITicker;
import org.libspark.betweenas3.core.tweens.AbstractTween;
import org.libspark.betweenas3.core.tweens.IITween;

class Matrix3DTween extends AbstractTween
{
    /**
    * static ITicker cache.
    */
    private static var _ticker:ITicker;

    /**
    * initial Matrix3D storage.
    */
    private var _start:Matrix3D;

    /**
    * DisplayObject.
    */
    public function get target():DisplayObject { return _target; }
    public function set target(value:DisplayObject):void {
        _start = value.transform.matrix3D.clone();
        _target = value;
    }
    private var _target:DisplayObject;

    /**
    * Tween easing.
    */
    public function get easing():IEasing { return _easing; }
    public function set easing(value:IEasing):void { _easing = value; }
    private var _easing:IEasing;

    /**
    * Destination transform matrix.
    */
    public function get matrix():Matrix3D { return _matrix; }
    public function set matrix(value:Matrix3D):void { _matrix = value; }
    private var _matrix:Matrix3D;

    /**
    * Set or get duration.
    */
    public function get time():Number { return _duration; }
    public function set time(value:Number):void { _duration = value; }

    /**
    * Constructor.
    *
    * @param duration sleep duration.
    * @param ticker   ticker object.
    * @param position initial position.
    */
    public function Matrix3DTween(ticker:ITicker = null, position:Number = 0) {
        if (!_ticker) {
            // create tmp tween to get the BetweenAS3's static ticker.
            var tmpTween:IITween = BetweenAS3.parallel() as IITween;
            _ticker = tmpTween.ticker;
        }

        super(ticker || _ticker, position);
    }

    /**
    * 更新処理を行う。
    */
    protected override function internalUpdate(time:Number):void
    {
        // check
        if (!_target) { throw new Error("target is not set"); }
        if (!_easing) { throw new Error("easing is not set"); }
        if (!_matrix) { throw new Error("matrix is not set"); }

        // get the factor (0.0~1.0)
        var factor:Number = 0.0;
        if (time > 0.0) {
            if (time < _duration) {
                factor = _easing.calculate(time, 0.0, 1.0, _duration);
            }
            else {
                factor = 1.0;
            }
        }

        // update the matrix
        _target.transform.matrix3D = interpolate(_start, _matrix, factor);
    }

    // forked from umhr's 【未完成】Matrix3D.interpolate(),
    // changed to handle matrices with scaling components (the builtin Matrix3D.interpolate doesn't)

    private function interpolate(thisMat:Matrix3D,toMat:Matrix3D,percent:Number):Matrix3D{
        var thisDecomp:Vector.<Vector3D> = thisMat.decompose("quaternion");
        var toDecomp:Vector.<Vector3D> = toMat.decompose("quaternion");
        
        var v0:Vector3D = thisDecomp[1];
        var v1:Vector3D = toDecomp[1];
        var cosOmega:Number = v0.w*v1.w + v0.x*v1.x + v0.y*v1.y + v0.z*v1.z;
        if(cosOmega < 0){
            v1.x = -v1.x;
            v1.y = -v1.y;
            v1.z = -v1.z;
            v1.w = -v1.w;
            cosOmega = -cosOmega;
        }
        var k0:Number;
        var k1:Number;
        if(cosOmega > 0.9999){
            k0 = 1 - percent;
            k1 = percent;
        }else{
            var sinOmega:Number = Math.sqrt(1 - cosOmega*cosOmega);
            var omega:Number = Math.atan2(sinOmega,cosOmega);
            var oneOverSinOmega:Number = 1/sinOmega;
            k0 = Math.sin((1-percent)*omega)*oneOverSinOmega;
            k1 = Math.sin(percent*omega)*oneOverSinOmega;
        }
        var scale_x:Number = thisDecomp[2].x*(1-percent) + toDecomp[2].x*percent;
        var scale_y:Number = thisDecomp[2].y*(1-percent) + toDecomp[2].y*percent;
        var scale_z:Number = thisDecomp[2].z*(1-percent) + toDecomp[2].z*percent;
        
        var tx:Number = thisDecomp[0].x*(1-percent) + toDecomp[0].x*percent;
        var ty:Number = thisDecomp[0].y*(1-percent) + toDecomp[0].y*percent;
        var tz:Number = thisDecomp[0].z*(1-percent) + toDecomp[0].z*percent;
        
        var x:Number = v0.x*k0+v1.x*k1;
        var y:Number = v0.y*k0+v1.y*k1;
        var z:Number = v0.z*k0+v1.z*k1;
        var w:Number = v0.w*k0+v1.w*k1;
        var _q:Vector.<Number> = new Vector.<Number>(16,true);
        _q[0] = (1-2*y*y-2*z*z)*scale_x;
        _q[1] = (2*x*y+2*w*z)*scale_x;
        _q[2] = (2*x*z-2*w*y)*scale_x;
        _q[3] = 0;
        _q[4] = (2*x*y-2*w*z)*scale_y;
        _q[5] = (1-2*x*x-2*z*z)*scale_y;
        _q[6] = (2*y*z+2*w*x)*scale_y;
        _q[7] = 0;
        _q[8] = (2*x*z+2*w*y)*scale_z;
        _q[9] = (2*y*z-2*w*x)*scale_z;
        _q[10] = (1-2*x*x-2*y*y)*scale_z;
        _q[11] = 0;
        _q[12] = tx;
        _q[13] = ty;
        _q[14] = tz;
        _q[15] = 1;
        
        return new Matrix3D(_q);
    }
}