forked from: [Alternativa3D] Collada Animation Sample

by ohisama forked from [Alternativa3D] Collada Animation Sample (diff: 390)
copyright (c) 2012 www.romatica.com
@author itoz ( http://www.romatica.com/ )

[AlternativaTemplate]
@see http://www.libspark.org/browser/as3/AlternativaTemplate
♥0 | Line 668 | Modified 2013-02-07 11:11:48 | MIT License
play

ActionScript3 source code

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

// forked from romatica's [Alternativa3D] Collada Animation Sample
/**
 * copyright (c) 2012 www.romatica.com
 * @author itoz ( http://www.romatica.com/ )
 * 
 *  [AlternativaTemplate]
 *  @see http://www.libspark.org/browser/as3/AlternativaTemplate
 *  
 */
package
{
    import a24.tween.Ease24;
    import a24.tween.Tween24;
    import alternativa.engine3d.animation.AnimationClip;
    import alternativa.engine3d.animation.AnimationController;
    import alternativa.engine3d.core.Camera3D;
    import alternativa.engine3d.core.Object3D;
    import alternativa.engine3d.core.Resource;
    import alternativa.engine3d.core.View;
    import alternativa.engine3d.lights.AmbientLight;
    import alternativa.engine3d.lights.OmniLight;
    import alternativa.engine3d.loaders.ParserCollada;
    import alternativa.engine3d.materials.TextureMaterial;
    import alternativa.engine3d.materials.VertexLightTextureMaterial;
    import alternativa.engine3d.objects.Skin;
    import alternativa.engine3d.primitives.Box;
    import alternativa.engine3d.resources.BitmapTextureResource;
    import jp.progression.data.getResourceById;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.display.Stage3D;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.MouseEvent;
    [SWF(backgroundColor="#ffffff", width="465", height="465", frameRate="60")]
    public class Wonderfl_Slime extends Sprite
    {
        private var stage3D : Stage3D;
        private var scene : Object3D;
        private var camera : Camera3D;
        private var container : Object3D;
        private var controllers : Array;
        private var cameraController : OrbitCameraController;
        private var jumpFlag : Boolean;
        private var _model : Skin;
        public function Wonderfl_Slime()
        {
            Wonderfl.disable_capture();
            if (stage) _initialize(null);
            else addEventListener(Event.ADDED_TO_STAGE, _initialize);
        }
        private function _initialize(event : Event) : void
        {
            removeEventListener(Event.ADDED_TO_STAGE, _initialize);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            var assetsLoader : AssetsLoader = AssetsLoader.getInstance();
            assetsLoader.addEventListener(Event.COMPLETE, onTexturesLoadComplete_Handler);
            assetsLoader.loadStart();
        }
        private function onTexturesLoadComplete_Handler(event : Event) : void
        {
            scene = new Object3D();
            camera = scene.addChild(new Camera3D(1, 1000)) as Camera3D;
            cameraController = new OrbitCameraController(camera, this, stage, stage);
            cameraController.mouseSensitivity = 0;
            cameraController.unbindAll();
            (cameraController as OrbitCameraController).bindBasicKey();
            cameraController.setObjectPosXYZ(0, -1000, 0);
            cameraController.lookAtXYZ(0, 0, 0);
            camera.view = addChild(new View(465, 465, true, 0x000000, 1, 4)) as View;
            camera.view.backgroundColor = 0x0;
            stage3D = stage.stage3Ds[0];
            stage3D.addEventListener(Event.CONTEXT3D_CREATE, onCreateContext_Handler, false, 0, true);
            stage3D.requestContext3D();
        }
        private function onCreateContext_Handler(evt : Event) : void
        {
            stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onCreateContext_Handler);
            createObject();
            createUI();
            addEventListener(Event.ENTER_FRAME, render, false, 0, true);
        }
        private function createUI() : void
        {
            var btn : MyButton = addChild(new MyButton("[JUMP]")) as MyButton;
            btn.addEventListener(MouseEvent.CLICK, onClickButton);
            var sw : Number = stage.stageWidth;
            var sh : Number = stage.stageHeight;
            var scx : int = (sw / 2);
            btn.x = scx -(btn.width / 2);
            btn.y= sh * 0.85 - btn.height ;
        }
        private function createObject() : void
        {
            container = scene.addChild(new Object3D())as Object3D;
            container.scaleX = container.scaleY = container.scaleZ = 2;
            container.z = -32;
            scene.addChild(new AmbientLight(0xd8d8d8))  as AmbientLight;
            var oLight : OmniLight = scene.addChild(new OmniLight(0xffffff, 100, 10000)) as OmniLight;
            oLight.x = -210;
            oLight.y = 20;
            oLight.z = 500;
            var grouudMaterial : TextureMaterial = new TextureMaterial(new BitmapTextureResource(getResourceById(AssetsLoader.GROUND_TEXTURE).data as BitmapData));
            var ground : Box = container.addChild(new Box(4, 4, 0.2, 2, 2, 2, false, grouudMaterial)) as Box;
            ground.scaleX = ground.scaleY = ground.scaleZ = 64;
            ground.z = -7;
            var texture : VertexLightTextureMaterial = new VertexLightTextureMaterial(new BitmapTextureResource(getResourceById(AssetsLoader.IMAGE_URL_MAIN).data as BitmapData));
            var data : XML = XML(getResourceById(AssetsLoader.DAE_MODEL_URL).data);
            var parser : ParserCollada = new ParserCollada();
            parser.parse(data, "", true);
            for (var i : int = 0; i < parser.objects.length; i++)
            {
                var obj : Object3D = parser.objects[i];
                scene.addChild(obj);
                if (parser.objects[i] as Skin )
                {
                    var skin : Skin = parser.objects[i] as Skin;
                    skin.setMaterialToAllSurfaces(texture);
                    _model = skin;
                    container.addChild(_model);
                }
            }
            controllers = [];
            for each (var animation : AnimationClip in parser.animations)
            {
                var controller : AnimationController = new AnimationController();
                controller.root = animation;
                controllers.push(controller);
            }
            for each (var resource:Resource in scene.getResources(true))
            {
                resource.upload(stage3D.context3D);
            }
        }
        private function onClickButton(event : MouseEvent) : void
        {
            if (jumpFlag) return ;
            jumpFlag = true;
            Tween24.serial(
                Tween24.tween(_model,0.1,Ease24._3_CubicIn).scaleZ(0.5).scale(1.3)
                ,Tween24.parallel(
                    Tween24.tween(_model,0.6,Ease24._BackInOut).$$z(100)
                    ,Tween24.tween(_model,0.65,Ease24._BackInOut).scaleZ(1.5).scale(0.7)
                )
                ,Tween24.parallel(
                    Tween24.tween(_model,0.8,Ease24._BounceOut).z(0)
                    ,Tween24.tween(_model,0.8,Ease24._BounceOut).scaleZ(0.9).scale(1)
                )
                ,Tween24.tween(_model,0.8,Ease24._BounceOut).scaleZ(1)
            ).onComplete(function():void{jumpFlag = false;}).play();
        }
        private function render(evt : Event) : void
        {
            for each (var controller : AnimationController in controllers)
            {
                controller.update();
            }
            camera.render(stage3D);
            cameraController.update();
        }
    }
}
import alternativa.engine3d.controllers.SimpleObjectController;
import alternativa.engine3d.core.Object3D;
import jp.progression.commands.lists.LoaderList;
import jp.progression.commands.net.LoadBitmapData;
import jp.progression.commands.net.LoadURL;
import flash.display.GradientType;
import flash.display.InteractiveObject;
import flash.display.SpreadMethod;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.filters.GlowFilter;
import flash.geom.Matrix;
import flash.geom.Vector3D;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.ui.Keyboard;
import flash.ui.Mouse;
import flash.ui.MouseCursor;
class MyButton extends Sprite
{
    public function MyButton(string : String, color : uint = 0xd8d8d8, w : int = 200, h : int = 35)
    {
        this.filters = [new GlowFilter(0x0, 0.5)];
        var gradType : String = GradientType.LINEAR;
        var gradMrx : Matrix = new Matrix();
        gradMrx.createGradientBox(w, h, Math.PI / 2, 0, 0);
        var gradColors : Array = [0xf5f5f5, color];
        var gradAlphas : Array = [1, 1];
        var gradRadios : Array = [0, 255];
        var gradSpread : String = SpreadMethod.PAD;
        this.graphics.beginGradientFill(gradType, gradColors, gradAlphas, gradRadios, gradMrx, gradSpread);
        this.graphics.drawRoundRect(0, 0, w, h, 15);
        this.graphics.endFill();
        this.addEventListener(MouseEvent.MOUSE_OVER, function(e:MouseEvent):void{(e.target as Sprite).alpha = 0.8;});
        this.addEventListener(MouseEvent.MOUSE_OUT, function(e:MouseEvent):void{(e.target as Sprite).alpha =1;});
        this.buttonMode = true;
        this.mouseChildren = false;
        var _label : TextField = this.addChild(new TextField()) as TextField;
        _label.defaultTextFormat = new TextFormat("_ゴシック", 12, 0x0);
        _label.autoSize = TextFieldAutoSize.LEFT;
        _label.text = string;
        _label.x = this.width / 2 - _label.width / 2;
        _label.y = this.height / 2 - _label.height / 2;
    }
}
class AssetsLoader extends EventDispatcher
{
    private var _startFlag : Boolean;
    private static const DOMAIN_PATH : String = "http://www.romatica.com/dev/wonderfl/slime/";
    public static const DAE_MODEL_URL : String = DOMAIN_PATH + "slimeBoneAnime.dae";
    public static const IMAGE_URL_MAIN : String = DOMAIN_PATH + "slime.png";
    public static const GROUND_TEXTURE : String = DOMAIN_PATH + "texture.png";
    public static var instance : AssetsLoader;
    public static function getInstance() : AssetsLoader
    {
        if ( instance == null ) instance = new  AssetsLoader(new SingletonEnforcer());
        return instance;
    }
    public function AssetsLoader(pvt : SingletonEnforcer)
    {
        if (pvt == null) throw new Error("TextureLoader is a singleton class, use getInstance() instead");
    }
    public function loadStart() : void
    {
        if (_startFlag) return;
        _startFlag = true;
        var loaderList : LoaderList = new LoaderList({
                onProgress:function():void{
                }                
                ,onComplete:function():void 
                {
                    dispatchEvent(new Event(Event.COMPLETE));
                }
                ,catchError:function(target:Object, e:Error):void
                {
                    trace( target, e );
                }
                ,onError:function():void
                {
                }
            });
        loaderList.addCommand(new LoadBitmapData(new URLRequest(IMAGE_URL_MAIN),{context: new LoaderContext(true)}));
        loaderList.addCommand(new LoadBitmapData(new URLRequest(GROUND_TEXTURE),{context: new LoaderContext(true)}));
        loaderList.addCommand(new LoadURL(new URLRequest(DAE_MODEL_URL), {context:new LoaderContext(true)}));
        loaderList.execute();
    }
}
internal class SingletonEnforcer
{
}
class CameraType
{
    public static const ORBIT : String = "orbit";
    public static const PANORAMA : String = "panorama";
    public static var TARGET : String = "target";
    public static var FREE : String = "free";
}
class OrbitCameraController extends SimpleObjectController
{
    public static const ACTION_FORWARD:String = "actionForward";
    public static const ACTION_BACKWARD:String = "actionBackward";
    private static const ROUND_VALUE:Number = 0.1;
    public function OrbitCameraController(
        targetObject:Object3D,
        mouseDownEventSource:InteractiveObject,
        mouseUpEventSource:InteractiveObject,
        keyEventSource:InteractiveObject,
        useKeyControl:Boolean = true,
        useMouseWheelControl:Boolean = true
        )
    {
        _target = targetObject;
        super(mouseDownEventSource, targetObject, 0, 3, mouseSensitivity);
        super.mouseSensitivity = 0;
        super.unbindAll();
        super.accelerate(true);
        this._mouseDownEventSource = mouseDownEventSource;
        this._mouseUpEventSource = mouseUpEventSource;
        this._keyEventSource = keyEventSource;
        _mouseDownEventSource.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
        if (useMouseWheelControl)
            _mouseDownEventSource.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
        if (useKeyControl)
        {
            _keyEventSource.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            _keyEventSource.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
        }
    }
    private var _easingSeparator:Number = 10;
    public function set easingSeparator(value:uint):void
    {
        if (value)
            _easingSeparator = value;
        else
            _easingSeparator = 1;
    }
    public var maxDistance:Number = 2000;
    public var maxLatitude:Number = 89.9;
    public var minDistance:Number = 200;
    public var minLatitude:Number = -89.9;
    private var _mouseSensitivityX:Number = -1;
    public function set mouseSensitivityX(value:Number):void
    {
        _mouseSensitivityX = value;
    }
    private var _mouseSensitivityY:Number = 1;
    public function set mouseSensitivityY(value:Number):void
    {
        _mouseSensitivityY = value;
    }
    public var multiplyValue:Number = 10;
    private var _needsRendering:Boolean;
    public function get needsRendering():Boolean
    {
        return _needsRendering;
    }
    private var _pitchSpeed:Number = 5;
    public function set pitchSpeed(value:Number):void
    {
        _pitchSpeed = value;
    }
    public var useHandCursor:Boolean = true;
    private var _yawSpeed:Number = 5;
    public function set yawSpeed(value:Number):void
    {
        _yawSpeed = value * Math.PI / 180;
    }
    public function set zoomSpeed(value:Number):void
    {
        _distanceSpeed = value;
    }
    private var _angleLatitude:Number = 0;
    private var _angleLongitude:Number = 0;
    private var _distanceSpeed:Number = 5;
    private var _keyEventSource:InteractiveObject;
    private var _lastLatitude:Number = 0;
    private var _lastLength:Number = 700;
    private var _lastLongitude:Number = _angleLongitude;
    private var _lastLookAtX:Number = _lookAtX;
    private var _lastLookAtY:Number = _lookAtY;
    private var _lastLookAtZ:Number = _lookAtZ;
    private var _length:Number = 700;
    private var _lookAtX:Number = 0;
    private var _lookAtY:Number = 0;
    private var _lookAtZ:Number = 0;
    private var _mouseDownEventSource:InteractiveObject;
    private var _mouseMove:Boolean;
    private var _mouseUpEventSource:InteractiveObject;
    private var _mouseX:Number;
    private var _mouseY:Number;
    private var _oldLatitude:Number;
    private var _oldLongitude:Number;
    private var _pitchDown:Boolean;
    private var _pitchUp:Boolean;
    private var _taregetDistanceValue:Number = 0;
    private var _taregetPitchValue:Number = 0;
    private var _taregetYawValue:Number = 0;
    private var _target:Object3D;
    private var _yawLeft:Boolean;
    private var _yawRight:Boolean;
    private var _zoomIn:Boolean;
    private var _zoomOut:Boolean;
    public function pitchUp():void
    {
        _taregetPitchValue = _pitchSpeed * multiplyValue;
    }
    public function pitchDown():void
    {
        _taregetPitchValue = _pitchSpeed * -multiplyValue;
    }
    public function yawLeft():void
    {
        _taregetYawValue = _yawSpeed * multiplyValue;
    }
    public function yawRight():void
    {
        _taregetYawValue = _yawSpeed * -multiplyValue;
    }
    public function moveForeward():void
    {
        _taregetDistanceValue -= _distanceSpeed * multiplyValue;
    }
    public function moveBackward():void
    {
        _taregetDistanceValue += _distanceSpeed * multiplyValue;
    }
    override public function bindKey(keyCode:uint, action:String):void
    {
        switch (action)
        {
            case ACTION_FORWARD:
            {
                keyBindings[keyCode] = toggleForward;
                break;
            }
            case ACTION_BACKWARD:
            {
                keyBindings[keyCode] = toggleBackward;
                break;
            }
            case ACTION_YAW_LEFT:
            {
                keyBindings[keyCode] = toggleYawLeft;
                break;
            }
            case ACTION_YAW_RIGHT:
            {
                keyBindings[keyCode] = toggleYawRight;
                break;
            }
            case ACTION_PITCH_DOWN:
            {
                keyBindings[keyCode] = togglePitchDown;
                break;
            }
            case ACTION_PITCH_UP:
            {
                keyBindings[keyCode] = togglePitchUp;
                break;
            }
        }
    }
    public function togglePitchDown(value:Boolean):void
    {
        _pitchDown = value;
    }
    public function togglePitchUp(value:Boolean):void
    {
        _pitchUp = value;
    }
    public function toggleYawLeft(value:Boolean):void
    {
        _yawLeft = value;
    }
    public function toggleYawRight(value:Boolean):void
    {
        _yawRight = value;
    }
    public function toggleForward(value:Boolean):void
    {
        _zoomIn = value;
    }
    public function toggleBackward(value:Boolean):void
    {
        _zoomOut = value;
    }
    override public function update():void
    {
        var oldAngleLatitude:Number = _angleLatitude;
        var oldAngleLongitude:Number = _angleLongitude;
        var oldLengh:Number = _lastLength;
        if (_zoomIn)
            _lastLength -= _distanceSpeed;
        else if (_zoomOut)
            _lastLength += _distanceSpeed;
        if (_taregetDistanceValue != 0)
        {
            _lastLength += _taregetDistanceValue;
            _taregetDistanceValue = 0;
        }
        if (_lastLength < minDistance)
            _lastLength = minDistance;
        else if (_lastLength > maxDistance)
            _lastLength = maxDistance;
        if (_lastLength - _length)
            _length += (_lastLength - _length) / _easingSeparator;

        if (Math.abs(_lastLength - _length) < ROUND_VALUE)
            _length = _lastLength;
        if (_mouseMove)
            _lastLongitude = _oldLongitude + (_mouseDownEventSource.mouseX - _mouseX) * _mouseSensitivityX;
        else if (_yawLeft)
            _lastLongitude += _yawSpeed;
        else if (_yawRight)
            _lastLongitude -= _yawSpeed;
        if (_taregetYawValue)
        {
            _lastLongitude += _taregetYawValue;
            _taregetYawValue = 0;
        }
        if (_lastLongitude - _angleLongitude)
            _angleLongitude += (_lastLongitude - _angleLongitude) / _easingSeparator;

        if (Math.abs(_lastLatitude - _angleLatitude) < ROUND_VALUE)
            _angleLatitude = _lastLatitude;
        if (_mouseMove)
            _lastLatitude = _oldLatitude + (_mouseDownEventSource.mouseY - _mouseY) * _mouseSensitivityY;
        else if (_pitchDown)
            _lastLatitude -= _pitchSpeed;
        else if (_pitchUp)
            _lastLatitude += _pitchSpeed;
        if (_taregetPitchValue)
        {
            _lastLatitude += _taregetPitchValue;
            _taregetPitchValue = 0;
        }
        _lastLatitude = Math.max(minLatitude, Math.min(_lastLatitude, maxLatitude));
        if (_lastLatitude - _angleLatitude)
            _angleLatitude += (_lastLatitude - _angleLatitude) / _easingSeparator;
        if (Math.abs(_lastLongitude - _angleLongitude) < ROUND_VALUE)
            _angleLongitude = _lastLongitude;
        var vec3d:Vector3D = this.translateGeoCoords(_angleLatitude, _angleLongitude, _length);
        _target.x = vec3d.x;
        _target.y = vec3d.y;
        _target.z = vec3d.z;
        if (_lastLookAtX - _lookAtX)
            _lookAtX += (_lastLookAtX - _lookAtX) / _easingSeparator;
        if (_lastLookAtY - _lookAtY)
            _lookAtY += (_lastLookAtY - _lookAtY) / _easingSeparator;
        if (_lastLookAtZ - _lookAtZ)
            _lookAtZ += (_lastLookAtZ - _lookAtZ) / _easingSeparator;
        updateObjectTransform();
        lookAtXYZ(_lookAtX, _lookAtY, _lookAtZ);
        _needsRendering = oldAngleLatitude != _angleLatitude
            || oldAngleLongitude != _angleLongitude
            || oldLengh != _length;
    }
    override public function startMouseLook():void
    {
    }
    override public function stopMouseLook():void
    {
    }
    public function lookAtPosition(x:Number, y:Number, z:Number, immediate:Boolean = false):void
    {
        if (immediate)
        {
            _lookAtX = x;
            _lookAtY = y;
            _lookAtZ = z;
        }
        _lastLookAtX = x;
        _lastLookAtY = y;
        _lastLookAtZ = z;
    }
    public function setLongitude(value:Number, immediate:Boolean = false):void
    {
        if (immediate)
            _angleLongitude = value;
        _lastLongitude = value;
    }
    public function setLatitude(value:Number, immediate:Boolean = false):void
    {
        value = Math.max(minLatitude, Math.min(maxLatitude, value));
        if (immediate)
            _angleLatitude = value;
        _lastLatitude = value;
    }
    public function setDistance(value:Number, immediate:Boolean = false):void
    {
        if (immediate)
            _length = value;
        _lastLength = value;
    }
    public function dispose():void
    {
        if (_mouseDownEventSource)
            _mouseDownEventSource.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
        if (_mouseDownEventSource)
            _mouseDownEventSource.removeEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
        if (_keyEventSource)
        {
            _keyEventSource.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            _keyEventSource.removeEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
        }
        _easingSeparator = 0;
        maxDistance = 0;
        minDistance = 0;
        _mouseSensitivityX = 0;
        _mouseSensitivityY = 0;
        multiplyValue = 0;
        _needsRendering = false;
        _pitchSpeed = 0;
        useHandCursor = false;
        _yawSpeed = 0;
        _angleLatitude = 0;
        _angleLongitude = 0;
        _distanceSpeed = 0;
        _keyEventSource = null;
        _lastLatitude = 0;
        _lastLength = 0;
        _lastLongitude = 0;
        _lastLookAtX = 0;
        _lastLookAtY = 0;
        _lastLookAtZ = 0;
        _length = 0;
        _lookAtX = 0;
        _lookAtY = 0;
        _lookAtZ = 0;
        _mouseDownEventSource = null;
        _mouseMove = false;
        _mouseUpEventSource = null;
        _mouseX = 0;
        _mouseY = 0;
        _oldLatitude = 0;
        _oldLongitude = 0;
        _pitchDown = false;
        _pitchUp = false;
        _taregetDistanceValue = 0;
        _taregetPitchValue = 0;
        _taregetYawValue = 0;
        _target = null;
        _yawLeft = false;
        _yawRight = false;
        _zoomIn = false;
        _zoomOut = false;
    }
    public function bindBasicKey():void
    {
        bindKey(Keyboard.LEFT, SimpleObjectController.ACTION_YAW_LEFT);
        bindKey(Keyboard.RIGHT, SimpleObjectController.ACTION_YAW_RIGHT);
        bindKey(Keyboard.DOWN, SimpleObjectController.ACTION_PITCH_DOWN);
        bindKey(Keyboard.UP, SimpleObjectController.ACTION_PITCH_UP);
        bindKey(Keyboard.PAGE_UP, OrbitCameraController.ACTION_BACKWARD);
        bindKey(Keyboard.PAGE_DOWN, OrbitCameraController.ACTION_FORWARD);
    }
    protected function mouseDownHandler(event:Event):void
    {
        _oldLongitude = _lastLongitude;
        _oldLatitude = _lastLatitude;
        _mouseX = _mouseDownEventSource.mouseX;
        _mouseY = _mouseDownEventSource.mouseY;
        _mouseMove = true;
        if (useHandCursor)
            Mouse.cursor = MouseCursor.HAND;
        _mouseUpEventSource.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
    }
    protected function mouseUpHandler(event:Event):void
    {
        if (useHandCursor)
            Mouse.cursor = MouseCursor.AUTO;
        _mouseMove = false;
        _mouseUpEventSource.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
    }
    private function keyDownHandler(event:KeyboardEvent):void
    {
        for (var key:String in keyBindings)
        {
            if (String(event.keyCode) == key)
                keyBindings[key](true);
        }
    }
    private function keyUpHandler(event:KeyboardEvent = null):void
    {
        for (var key:String in keyBindings)
            keyBindings[key](false);
    }
    private function mouseWheelHandler(event:MouseEvent):void
    {
        _lastLength -= event.delta * 20;
        if (_lastLength < minDistance)
            _lastLength = minDistance;
        else if (_lastLength > maxDistance)
            _lastLength = maxDistance;
    }
    private function translateGeoCoords(latitude:Number, longitude:Number, radius:Number):Vector3D
    {
        const latitudeDegreeOffset:Number = 90;
        const longitudeDegreeOffset:Number = -90;
        latitude = Math.PI * latitude / 180;
        longitude = Math.PI * longitude / 180;
        latitude -= (latitudeDegreeOffset * (Math.PI / 180));
        longitude -= (longitudeDegreeOffset * (Math.PI / 180));
        var x:Number = radius * Math.sin(latitude) * Math.cos(longitude);
        var y:Number = radius * Math.cos(latitude);
        var z:Number = radius * Math.sin(latitude) * Math.sin(longitude);
        return new Vector3D(x, z, y);
    }
}