forked from: Human Theatre

by jmbyh521 forked from Human Theatre (diff: 1)
♥0 | Line 833 | Modified 2015-09-08 16:20:52 | MIT License | (replaced)
play

ActionScript3 source code

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

// forked from Loth2012's Human Theatre
package {
    import away3d.animators.transitions.CrossfadeStateTransition;
    import away3d.animators.SkeletonAnimationState;
    import away3d.animators.SkeletonAnimationSet;
    import away3d.animators.SkeletonAnimator;
    import away3d.animators.data.Skeleton;
    import away3d.lights.shadowmaps.NearDirectionalShadowMapper;
    import away3d.materials.methods.FilteredShadowMapMethod;
    import away3d.materials.methods.NearShadowMapMethod;
    import away3d.core.managers.Stage3DManager;
    import away3d.core.managers.Stage3DProxy;
    import away3d.containers.ObjectContainer3D;
    import away3d.events.Stage3DEvent;
    import away3d.entities.Mesh;
    import away3d.debug.AwayStats;
    import away3d.primitives.SkyBox;
    import away3d.lights.LightBase;
    import away3d.loaders.Loader3D;
    import away3d.lights.LightProbe;
    import away3d.lights.PointLight;
    import away3d.events.LoaderEvent;
    import away3d.containers.View3D;
    import away3d.events.AssetEvent;
    import away3d.core.base.Geometry;
    import away3d.events.MouseEvent3D;
    import away3d.library.AssetLibrary;
    import away3d.materials.LightSources;
    import away3d.textures.BitmapTexture;
    import away3d.materials.ColorMaterial;
    import away3d.lights.DirectionalLight;
    import away3d.library.assets.AssetType;
    import away3d.loaders.parsers.AWD2Parser;
    import away3d.materials.methods.FogMethod;
    import away3d.materials.methods.OutlineMethod;
    import away3d.materials.methods.CelDiffuseMethod;
    import away3d.materials.methods.CelSpecularMethod;
    import away3d.materials.methods.EnvMapMethod;
    import away3d.materials.methods.LightMapMethod;
    import away3d.materials.methods.FresnelSpecularMethod;
    import away3d.materials.methods.TripleFilteredShadowMapMethod;
    import away3d.materials.lightpickers.StaticLightPicker;
    import away3d.cameras.lenses.PerspectiveLens;
    import away3d.materials.DefaultMaterialBase;
    import away3d.controllers.HoverController;
    import away3d.materials.TextureMaterial;
    import away3d.primitives.SphereGeometry;
    import away3d.primitives.PlaneGeometry;
    
    import org.flintparticles.integration.away3d.v4.A3D4Renderer;
    
    import flash.filters.DropShadowFilter;
    import flash.display.StageScaleMode;
    import flash.display.StageQuality;
    import flash.events.KeyboardEvent;
    import flash.display.BitmapData;
    import flash.display.StageAlign;
    import flash.display.MovieClip;
    import flash.events.MouseEvent;
    import flash.text.TextFormat;
    import flash.text.TextField;
    import flash.display.LoaderInfo;
    import flash.display.Bitmap;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.display.Shape;
    import flash.geom.Vector3D;
    import flash.events.Event;
    import flash.geom.Matrix;
    import flash.ui.Keyboard;
    import flash.net.URLRequest;
    import flash.display.DisplayObject;
    import flash.events.ProgressEvent;
    import flash.net.URLLoader;
    import flash.net.URLLoaderDataFormat;
    import flash.system.LoaderContext;
    /**
     * 
     * HUMAN THEATRE beta 0.1
     * 
     * One AWD2 file from max
     * Two animated model of man and woman on the same squeleton
     * Multy clone technique with self animation 
     * 
     * Code, Model and map by LoTh
     * Blog : http://3dflashlo.wordpress.com
     *
     */
    public class HumanTheatre extends Sprite {
        private static const SCALE:Number = 16;
        private static var COLOR:Object = {
            sun : 0xFFFFEF, moon : 0x33FF80,
            sky : 0xFFFFFF , ground : 0x6D6145,
            background : 0x000000 , fog : 0xAEAEA8
        }
        private static var DemoAmbiant:Array = [0.85, 0.1];
        private static var DemoDiffuse:Array = [1, 1];
        private static var DemoSpecular:Array = [1, 0.5];
        private static var _capture : Bitmap;
        private static var _player:Mesh;
        // mapping online
        private static const MESH_PATH:String = 'http://3dflashlo.free.fr/wonderfl/assets/';
        private static const PATH:String = "http://assets.wonderfl.net/images/related_images/"
        private static const FILES:Array =[
        '/f/f1/f1ad/f1ad270ccefb2f72a1a770c69e2003baf4c525ab', '/3/3a/3a97/3a97741efaeeb0f3a556cc39a305fe4278b73e94',
        '/b/b3/b321/b3216c9e0d279b0103e17c780f1c62cfd7e44e6d', '/9/92/92ff/92ffe84a7ebdc2c8841337d9f0fe8cf9cc0e9efa',
        ];
        // mapping Local
        private static const PATH_LOCAL:String = 'assets/';
        private static const FILES_LOCAL:Array = [ 'amphy.jpg', 'front.jpg', 'man.jpg', 'woman.jpg'];
        private static var _local:Boolean = false;
        // engine
        protected static var _lightPicker:StaticLightPicker;
        protected static var _hoverCtrl:HoverController;
        protected static var _stage3DProxy:Stage3DProxy;
        protected static var _manager:Stage3DManager;
        protected static var _stats:AwayStats;
        protected static var _skyBox:SkyBox;
        protected static var _view:View3D;
        // referency
        private var _materialMan:Vector.<DefaultMaterialBase>;
        private var _materialWoman:Vector.<DefaultMaterialBase>;
        private var _materials:Vector.<DefaultMaterialBase>;
        private var _mapList:Vector.<BitmapData>;
        private var _light:Array;
        private var _n:int;
        private var _i:int;
        // animation
        //private var animator:SkeletonAnimator;
        private var _squeleton:Skeleton;
        private var _animationSet:SkeletonAnimationSet;
        private var stateTransition:CrossfadeStateTransition = new CrossfadeStateTransition(0.5);
        // character movement
        private var currentRotationInc:Number = 0;
        private var movementDirection:Number;
        private var isRunning:Boolean;
        private var isMoving:Boolean;
        private var isJumping:Boolean;
        private var currentAnim:String;
        // animation constants
        private static const SEQUENCE:Array = ['Breathe', 'Sit', 'SitWoman' , 'Walk', 'Run'];
        private static const SEQUENCE_MAN:Array = ['Breathe', 'Sit', 'Walk', 'Run'];
        private static const SEQUENCE_WOMEN:Array = ['Breathe', 'SitWoman', 'WalkWoman', 'Run'];
        private static const SEQSPEED:Array = [0.5, 1, 1, 0.5, 0.5, 0.5, 0.5, 0.5];
        private static const ROTATION_SPEED:Number = 10;
        private static const XFADE_TIME:Number = 0.5;
        // scene objects
        private var _hero:Mesh;
        private var _box:Mesh;
        private var _deco:Mesh;
        private var _decoFront:Mesh;
        // Avatar referency
        private var _skinMesh:Vector.<Mesh>;
        private var _cloneAnim:Vector.<SkeletonAnimator>;
        private var _cloneHair:Vector.<Mesh>;
        private var _cloneStyleMan:Vector.<Mesh>;
        private var _cloneStyleWoman:Vector.<Mesh>;
        // Particule container
        private var emitter:EmitterSmoke;
        private var particleContainer:ObjectContainer3D;
        private var particleRenderer:A3D4Renderer;
        // navigation
        private var _prevMouseX:Number;
        private var _prevMouseY:Number;
        private var _mouseMove:Boolean;
        private var _cameraHeight:Number = 0;
        
        private var _eyePosition:Vector3D;
        private var _mapper:Mapper;
        private var _text:TextField;
        
        private var _fog:FogMethod;
        private var _reflect:EnvMapMethod;
        private var _specularMethod:FresnelSpecularMethod;
        private var _shadowMethod:NearShadowMapMethod;
        private var photoLoad:PhotoLoader;
        
        /** Constructor */
        public function HumanTheatre() {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
        }
        
        private function init(e:Event = null):void{
            removeEventListener(Event.ADDED_TO_STAGE, init);
            stage.align = 'TL';
            stage.scaleMode = 'noScale';
            stage.quality = 'low';
            stage.frameRate = 60;
            stage.color = COLOR.background;
            // ★ wonderfl capture
            Wonderfl.disable_capture();
            //_capture = addChild(new Bitmap(new BitmapData(465, 465, false, 0x000000))) as Bitmap ;
            _manager = Stage3DManager.getInstance(stage);
            _stage3DProxy = _manager.getFreeStage3DProxy();
            _stage3DProxy.addEventListener(Stage3DEvent.CONTEXT3D_CREATED, onContextCreated);
        }
        
        private function onContextCreated(e:Stage3DEvent):void{
            _stage3DProxy.color = COLOR.background;
            _stage3DProxy.antiAlias = 4;
            initEngine();
            initText();
            initLights();
            initListeners();
            
            // start by loading all bitmap
            _mapList = new Vector.<BitmapData>();
            loadBitmap();
            
            // character mesh referency
            _skinMesh = new Vector.<Mesh>();
            // hair style clone referency
            _cloneStyleMan = new Vector.<Mesh>();
            _cloneStyleWoman = new Vector.<Mesh>();
            
        }
        
        //-------------------------------- AWAY3D
        
        /** Initialise the engine */
        private function initEngine():void {
            _view = new View3D();
            _view.stage3DProxy = _stage3DProxy;
            _view.shareContext = true;
            _view.backgroundColor = COLOR.background;
            
            _view.camera.lens = new PerspectiveLens(80);
            _view.camera.lens.far = 20000;
            _view.camera.lens.near = 1;
            
            _hoverCtrl = new HoverController(_view.camera, null, 180, 0, 100*SCALE, 6, 90);
            _hoverCtrl.tiltAngle = 0;
            _hoverCtrl.panAngle = 180;
            _hoverCtrl.minTiltAngle = -60;
            _hoverCtrl.maxTiltAngle = 60;
            _hoverCtrl.autoUpdate = false;
            
            addChild(_view);
            
            //away3d stat
            _stats = new AwayStats(_view, false, true);
            _stats.alpha = 0.3;
            addChild(_stats);
            
            //material reference
            _materials = new Vector.<DefaultMaterialBase>();
            _materialMan = new Vector.<DefaultMaterialBase>();
            _materialWoman = new Vector.<DefaultMaterialBase>();
            //light referency
            _light = [];
            // hero content
            _player = new Mesh(new Geometry());
            _view.scene.addChild(_player);
            _player.y = 0//20 * SCALE;
            //auto map generator
            _mapper = new Mapper();
            
        }
        
        //-------------------------------- PARTICULE
        
        private function addParticule():void {
            // flint
            emitter = new EmitterSmoke(this);
            emitter.start();
            
            // Create Particle Container
            particleContainer = new ObjectContainer3D();
            particleContainer.visible = true;
            _view.scene.addChild(particleContainer);
            
            particleRenderer = new A3D4Renderer(particleContainer);
            particleRenderer.addEmitter(emitter);
        }
        
        //-------------------------------- LOOP
        
        /** Render loop */
        private function onEnterFrame(event:Event):void {
            //update character animation
            _player.rotationY += currentRotationInc;
            _hoverCtrl.lookAtPosition = new Vector3D(_player.x,  _player.y + (30 * SCALE), _player.z);
            updateClone();
            
            //update camera controler
            _hoverCtrl.update();
            //update light
            //_light[1].position = _view.camera.position;
            //update view
            _view.render();
            // ★ wonderfl capture
            if (_capture) _stage3DProxy.context3D.drawToBitmapData(_capture.bitmapData);
        }
        
        //-------------------------------- LISTENER
        
        /** Initialise the listeners */
        private function initListeners():void {
            //add render loop
            _stage3DProxy.addEventListener(Event.ENTER_FRAME, onEnterFrame, false, 0, true);
            //add key listeners
            stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp, false, 0, true);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, false, 0, true);
            //navigation
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown, false, 0, true);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove, false, 0, true);
            stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseLeave, false, 0, true);
            stage.addEventListener(MouseEvent.MOUSE_WHEEL, onStageMouseWheel, false, 0, true)
            stage.addEventListener(Event.MOUSE_LEAVE, onStageMouseLeave, false, 0, true);
            //add resize event
            stage.addEventListener(Event.RESIZE, onResize, false, 0, true);
            onResize();
        }
        
        //-------------------------------- LIGHT
        
        /** Initialise the lights */
        private function initLights():void {
            //create a light for shadows that mimics the sun's position in the skybox
            var sun:DirectionalLight = new DirectionalLight(0.1, -1, 0.35);
            sun.castsShadows = true;
            sun.shadowMapper = new NearDirectionalShadowMapper(0.3);
            _view.scene.addChild(sun);
            _light.push(sun);
            //create a light for ambient effect that mimics the sky
            var moon:PointLight = new PointLight();
            moon.y = -600*SCALE;
            moon.radius = 200;
            moon.fallOff = 2500;
            _view.scene.addChild(moon);
            _light.push(moon);
            makeSky();
        }
        
        //-------------------------------- SKY
        
        /** sky change */
        private function randomSky():void {
            COLOR.ground = 0xFFFFFF * Math.random();
            COLOR.fog = 0xFFFFFF * Math.random();
            COLOR.sky = 0xFFFFFF * Math.random();
            COLOR.sun = 0xFFFFFF * Math.random();
            COLOR.moon = 0xFFFFFF * Math.random();
            DemoAmbiant = [0.4, 0.3];
            DemoAmbiant = [Math.random(), Math.random()];
            DemoDiffuse = [Math.random(), Math.random()];
            DemoSpecular = [Math.random() * 4, Math.random() * 2];
            makeSky();
        }
        
        private function makeSky():void {
            if (_light[2]) {
                _view.scene.removeChild(_light[2]);
                _light.pop();
            }
            if (_skyBox) {
                _view.scene.removeChild(_skyBox);
                _skyBox.dispose();
            }
            //generate vector degrade sky
            _mapper.vectorSky([COLOR.ground, COLOR.fog, COLOR.sky], 8);
            
            _skyBox = new SkyBox(_mapper.sky);
            _view.scene.addChild(_skyBox);
            //add new probe light
            var probe:LightProbe = new LightProbe(_mapper.sky);
            _view.scene.addChild(probe);
            _light.push(probe);
            //sun
            _light[0].color = COLOR.sun;
            _light[0].ambientColor = COLOR.fog;
            _light[0].ambient = DemoAmbiant[0];
            _light[0].diffuse = DemoDiffuse[0];
            _light[0].specular = DemoSpecular[0];
            // moon
            _light[1].color = COLOR.moon;
            _light[1].ambientColor = COLOR.ground;
            _light[1].ambient = DemoAmbiant[1];
            _light[1].diffuse = DemoDiffuse[1];
            _light[1].specular = DemoSpecular[1];
            _lightPicker = new StaticLightPicker(_light);
            
            for each (var o:DefaultMaterialBase in _materials) {
                o.lightPicker = _lightPicker;
            }
            if(_fog) _fog.fogColor = COLOR.fog;
        }
        
        //-------------------------------- MATERIAL
        
        /** Initialise the material */
        protected function initMaterial():void {
            // global methode
            _fog = new FogMethod(200*SCALE, 2000*SCALE, COLOR.fog);
            //_reflect = new EnvMapMethod(_mapper.sky, 0.5)
            _specularMethod = new FresnelSpecularMethod();
            _specularMethod.normalReflectance = 0.3
            // global shadow
            _shadowMethod = new NearShadowMapMethod(new FilteredShadowMapMethod(_light[0]), 0.05);
            _shadowMethod.epsilon = .0007;
            
            var material:DefaultMaterialBase;
            
            // 0 - ground
            var grid:Shape = new Shape();
            grid.graphics.beginFill(0x333333, 0.3);
            grid.graphics.drawRect(0, 0, 4, 128);
            grid.graphics.drawRect(0, 0, 128, 4);
            var b:BitmapData = new BitmapData(128, 128, false, 0x91825F);
            b.draw(grid);
            material = materialFromBitmap('ground', [b, b, b], true, false);
            material.ambient = 1;
            material.gloss = 30;
            material.specular = 1;
            material.repeat = true;
            
            // 1 - Hero
            var bsize:int = 512;
           /* grid.graphics.clear();
            grid.graphics.beginFill(0xAAAAAA, 1);//full
            grid.graphics.drawRect(0, 0, bsize, bsize);
            grid.graphics.beginFill(0xAA8000, 1);//head
            grid.graphics.drawRect(0, 0, bsize, 178);
            grid.graphics.beginFill(0xEEEEEE, 1);//shirt
            grid.graphics.drawRect(0, 178, bsize, 160);
            grid.graphics.beginFill(0x333333, 1);//shoes
            grid.graphics.drawRect(0, 472, bsize, 40);
            var g:Bitmap = new Bitmap(_mapList[2]);
            var f:Sprite = new Sprite();
            f.addChild(g);
            f.addChild(grid);
            grid.blendMode = 'multiply';
            
            var b:BitmapData = new BitmapData(512, 512, false, 0x606060);
            b.draw(f);*/
            material = materialFromBitmap('hero', [_mapList[2]], false, false, false, true);
            material.gloss = 10;
            material.specular = 0.2;
            material.ambient = 1;
            
            // 2 - Amphy
            material = materialFromBitmap('amphy', [_mapList[0]], false, false, false, true);
            material.ambient = 1;
            material.gloss = 100;
            material.specular = 0.1;
            
             // 3 - Amphy front
            material = materialFromBitmap('front', [_mapList[1]], false, false, false, true);
            material.ambient = 1;
            material.gloss = 30;
            material.specular = 0.2;
            
            // 4 _ hair
            grid.graphics.clear();
            grid.graphics.beginFill(0x333333, 1);//full
            grid.graphics.drawRect(0, 0, bsize, bsize);
            b = new BitmapData(512, 512, false, 0x202020);
            b.draw(grid);
            material = materialFromBitmap('hair', [b], false, false, false, true);
            material.ambient = 1;
            material.gloss = 10;
            material.specular = 0.2;
            
            // 5_woman
            material = materialFromBitmap('hero', [_mapList[3]], false, false, false, true);
            material.gloss = 10;
            material.specular = 0.2;
            material.ambient = 1;
        }
        
        /** Make Material from bitmap */
        protected function materialFromBitmap(name:String, Bitmaps:Array, Norm:Boolean = false, Spec:Boolean = false, Occ:Boolean = false, cartoon:Boolean = false):DefaultMaterialBase {
            var n:int;
            var material:TextureMaterial = new TextureMaterial(new BitmapTexture(Bitmaps[0]));
            // normal map
            if (Norm) { n = 1; material.normalMap = new BitmapTexture(Bitmaps[n]); }
            // specular map 
            if (Spec) { n = 2; material.specularMap = new BitmapTexture(Bitmaps[n]); }
            // occlusion
            if (Occ) { n = 3; material.addMethod(new LightMapMethod(new BitmapTexture(Bitmaps[n]))); }
            
            material.name = name;
            material.lightPicker = _lightPicker;
            material.diffuseLightSources = LightSources.PROBES;
            material.specularLightSources = LightSources.LIGHTS;
           // material.specularMethod = _specularMethod;
            material.shadowMethod = _shadowMethod;
            
            if (cartoon) {
                    material.addMethod(new OutlineMethod(0x000000, 0.2, true));
                   // material.diffuseMethod = new CelDiffuseMethod(3);
                  // CelDiffuseMethod(material.diffuseMethod).smoothness = .3;
                  //material.specularMethod = new CelSpecularMethod(.2);
                    //CelSpecularMethod(material.specularMethod).smoothness = .3;
            }
            material.addMethod(_fog);
            //push to reference
            _materials.push(material);
            return material;
        }
        
        //-------------------------------- BINARY LOADER
        
        /** Global Load Binary file */
        private function load(url:String):void {
            var loader:URLLoader = new URLLoader();
            var extention:String = url.substring(url.length - 3);
            loader.dataFormat = URLLoaderDataFormat.BINARY;
            if(extention == 'awd') loader.addEventListener(Event.COMPLETE, parseAWD, false, 0, true);
            loader.addEventListener(ProgressEvent.PROGRESS, loadProgress, false, 0, true);
            loader.load(new URLRequest(url));
        }
        
        /** Display current load */
        private function loadProgress(e:ProgressEvent):void {
            var P:int = int(e.bytesLoaded / e.bytesTotal * 100);
            if (P != 100) log('Load : ' + P + ' % | ' + int((e.bytesLoaded / 1024) << 0) + ' ko\n');
            else message();
        }
        
        //-------------------------------- BITMAP DISPLAY
        
        /** load bitmap from WonderFl or Local */
        public function loadBitmap():void {
            _n = 0;
            photoLoad = new PhotoLoader();
            completeBitmap(); // start first
        }
        
        protected function completeBitmap(e:Event=null):void {
            if (e) {
                var f:Bitmap = new Bitmap(photoLoad.content);
                _mapList.push(f.bitmapData);
                _n++;
            }
            if (FILES[_n]){ 
                log("image " + _n);
                photoLoad = new PhotoLoader();
                photoLoad.addEventListener(PhotoLoader.COMPLETE, completeBitmap, false, 0, true);
                if (_local) photoLoad.load(PATH_LOCAL + FILES_LOCAL[_n]);
                else photoLoad.load(PATH+FILES[_n]);
            } else {
               // create material
               initMaterial();
               // start Loading AWD
               if (_local) load(PATH_LOCAL + "simple.awd");
               else load(MESH_PATH+"simple.awd");
            }
        }
        
        //-------------------------------- AWD DISPLAY
        
        /** Load AWD */
        private function parseAWD(e:Event):void {
            var loader:URLLoader = e.target as URLLoader
            var loader3d:Loader3D = new Loader3D(false);
            loader3d.addEventListener(AssetEvent.ASSET_COMPLETE, onAssetComplete, false, 0, true);
            loader3d.addEventListener(LoaderEvent.RESOURCE_COMPLETE, finalAWD, false, 0, true);
            loader3d.loadData(loader.data, null, null, new AWD2Parser());
            loader.removeEventListener(ProgressEvent.PROGRESS, loadProgress);
            loader.removeEventListener(Event.COMPLETE, parseAWD);
            loader = null;
        }
        
        /** Listener function for asset complete event on awd */
        private function onAssetComplete(event:AssetEvent):void {
            var mesh:Mesh;
            var material:TextureMaterial;
            var specularMethod:FresnelSpecularMethod;
            // ++ Skeleton referency same for man and woman
            if (event.asset.assetType == AssetType.SKELETON) {
                _animationSet = new SkeletonAnimationSet(2);
                _squeleton = event.asset as Skeleton;
            // ++ Animations create state objects for each animation state encountered 
            } else if (event.asset.assetType == AssetType.ANIMATION_STATE) {
                var animationState:SkeletonAnimationState = event.asset as SkeletonAnimationState;
                _animationSet.addState(animationState.name, animationState);
            // ++ Mesh
            } else if (event.asset.assetType == AssetType.MESH) {
                mesh = Mesh(event.asset);
                // Character Men & Woman
                if (mesh.name.substring(0, 4) == "Skin") {
                        mesh.scale(SCALE * 0.45);
                        if (mesh.name == 'Skin_Man') mesh.material = _materials[1];
                        if (mesh.name == 'Skin_Woman') mesh.material = _materials[5];
                        _skinMesh.push(mesh);
                }
                // Character hair no scale because hero child 
                if (mesh.name.substring(0, 8) == "Hair_Man") {
                    mesh.material = _materials[4];
                    _cloneStyleMan.push(mesh);
                }
                if (mesh.name.substring(0, 8) == "Hair_Wom") {
                    mesh.material = _materials[4];
                    _cloneStyleWoman.push(mesh);
                }
                // Scene decoration
                if (mesh.name == "Deco") {
                    _deco = mesh;
                    _deco.material = _materials[2];
                    _deco.scale(SCALE);
                }
                if (mesh.name == "DecoFront") {
                    _decoFront = mesh;
                    _decoFront.material = _materials[3];
                    _decoFront.scale(SCALE);
                }
                if (mesh.name == "Box") {
                    _box = mesh;
                    _box.material = _materials[0];
                    _box.castsShadows = false;
                    _box.geometry.scaleUV(50, 50);
                    _box.scale(SCALE);
                }
                
            }
        }
        
        /** Check if all resourse loaded */
        private function finalAWD(e:LoaderEvent):void {
            var loader3d:Loader3D = e.target as Loader3D;
            loader3d.removeEventListener(AssetEvent.ASSET_COMPLETE, onAssetComplete);
            loader3d.removeEventListener(LoaderEvent.RESOURCE_COMPLETE, finalAWD);
            
            _view.scene.addChild(_deco);
            _view.scene.addChild(_decoFront);
            _view.scene.addChild(_box);
            
            // add people in theatre
            populateTheatre();
            
            // add player avatar
            _hero = addAvatar({target:_player});
            rest();
            
            addParticule();
        }
        
        //-------------------------------- CLONE AVATAR
        
        /** Duplicate Man or Woman into Avatar with self animation */
        public function addAvatar(o:Object = null):Mesh {
            if (o == null) o = new Object();
            if(!_cloneAnim)_cloneAnim = new Vector.<SkeletonAnimator>();
            if(!_cloneHair)_cloneHair = new Vector.<Mesh>();
            
            var sex:int = o.sex || rand(1);// 0:man 1:woman
            var hair:Mesh; 
            var skin:Mesh = Mesh((_skinMesh[sex]).clone());
            // position & rotation
            if(o.rot!=null)skin.yaw(o.rot.y || 0);
            skin.position = o.pos || new Vector3D();
            
            if (o.target!=null) o.target.addChild(skin);
            else _view.scene.addChild(skin);
            
            // choose random hair style;
            if (o.hair==null) o.hair = true;
            if(o.hair){
            if (sex == 0) hair = Mesh((_cloneStyleMan[rand(_cloneStyleMan.length - 1)]).clone());
            else hair = Mesh((_cloneStyleWoman[rand(_cloneStyleWoman.length - 1)]).clone());
            _cloneHair.push(hair);
            skin.addChild(hair);
            }
            // create new animator
            var animatorX:SkeletonAnimator = new SkeletonAnimator(_animationSet, _squeleton);
            animatorX.updateRootPosition = false;
            if(o.hair)_cloneAnim.push(animatorX);
            
            // play random animation
            var num:int = o.anim || (int(Math.random() * 2));
            var anim:String;
            if (sex == 0) anim = SEQUENCE_MAN[num];
            else anim = SEQUENCE_WOMEN[num];
            animatorX.playbackSpeed = o.speed || -SEQSPEED[num];
            animatorX.play(anim, stateTransition);
            skin.animator = animatorX;
            return skin;
        }
        
        /** Special populate for Theatre */
        private function populateTheatre(n:int = 11):void {
            var list:Vector.<Object> = new Vector.<Object>();
            var r:int, d:int = 200, nh:int = 45, obj:Object;
            for (var j:int = 1; j < n; j++) {
                if (j == 1) { nh = 16; d = 80; }
                if (j == 2) { nh = 22; d = 100; }
                if (j == 3) { nh = 24; d = 120; }
                if (j == 4) { nh = 26; d = 140; }
                if (j == 5) { nh = 30; d = 160; }
                if (j == 6) { nh = 35; d = 180; }
                if (j == 7) { nh = 40; d = 200; }
                for (_i = 1; _i < nh; _i++) {
                    r = -30 + ( _i * (240 / nh));
                    obj = new Object();
                    obj['rot'] = new Vector3D(0, 90 - r, 0);
                    if (j < 7) obj['pos'] = orbit( 90, r , (d + 5) * SCALE, (20 * SCALE) + (j * (20 * SCALE)));
                    else obj['pos'] = orbit( 90, r , (d + 5) * SCALE,  (20 * SCALE) + (j * (20 * SCALE) ) + ((j - 7) * (40 * SCALE)) );
                    list.push(obj);
                }
            }
            var avatar:Mesh;
            for (_i = 0; _i < list.length; _i++ ) {
                avatar = addAvatar(list[_i])
            }
        }
        
        /** Update Hair animation to follow head bone */
        private function updateClone():void {
            var anim:SkeletonAnimator;
            for (_i = 0; _i < _cloneAnim.length; _i++) {
                anim = _cloneAnim[_i];
                if (anim.globalPose.numJointPoses == 25)
                _cloneHair[_i].transform = anim.globalPose.jointPoses[24].toMatrix3D();
            }
        }
        
        //-------------------------------- ANIMATION
        
        /** Character breath animation */
        private function rest():void {
            isMoving = false;
            _hero.animator.playbackSpeed = SEQSPEED[0];
            if (currentAnim == SEQUENCE[0]) return;
            currentAnim = SEQUENCE[0];
            _hero.animator.play(currentAnim, stateTransition);
        }
        
        /** Character fight animation */
        private function fight():void {
            if (currentAnim == SEQUENCE[3]) return;
            currentAnim = SEQUENCE[3];
            _hero.animator.playbackSpeed = SEQSPEED[3];
            _hero.animator.play(currentAnim, stateTransition);
        }
        
        /** Character fight animation */
        private function fight2():void {
            if (currentAnim == SEQUENCE[4]) return;
            currentAnim = SEQUENCE[4];
            _hero.animator.playbackSpeed = SEQSPEED[4];
            _hero.animator.play(currentAnim, stateTransition);
        }
        
        /** Character jump animation */
        private function jump():void {
            isJumping = false;
        }
        
        /** Get animation index in SEQUENCE */
        private function getAnim(name:String):int {
            var n:int;
            for (_i = 0; _i < SEQUENCE.length; _i++)
                if (SEQUENCE[_i] == name) n = _i;
            return n;
        }
        
        /** Character Mouvement */
        private function updateMovement(dir:Number):void {
            isMoving = true;
            var anim:String = isRunning ? 'Run' : 'Walk';
            _hero.animator.playbackSpeed = dir * SEQSPEED[getAnim(anim)];
            if (currentAnim == anim) return;
            currentAnim = anim;
            _hero.animator.play(currentAnim, stateTransition);
        }
        
        //-------------------------------- KEYBORD
        
        /** Key down listener for player animation */
        private function onKeyDown(event:KeyboardEvent):void {
            switch (event.keyCode) {
                case Keyboard.SHIFT: 
                    isRunning = true;
                    if (isMoving)
                        updateMovement(movementDirection);
                    break;
                case Keyboard.UP: case Keyboard.W: case Keyboard.Z: //fr
                    updateMovement(movementDirection = 1);
                    break;
                case Keyboard.DOWN: case Keyboard.S: 
                    updateMovement(movementDirection = -1);
                    break;
                case Keyboard.LEFT: case Keyboard.A: case Keyboard.Q: //fr
                    currentRotationInc = -ROTATION_SPEED;
                    break;
                case Keyboard.RIGHT: case Keyboard.D: 
                    currentRotationInc = ROTATION_SPEED;
                    break;
                case Keyboard.E: 
                    fight2();
                    break;
                case Keyboard.SPACE: case Keyboard.R: 
                    fight();
                    break;
                case Keyboard.N: 
                    randomSky();
                    break;
                case Keyboard.B: 
                   // makeClone();
                    break;
            }
        }
        
        /** Key up listener */
        private function onKeyUp(event:KeyboardEvent):void {
            switch (event.keyCode) {
                case Keyboard.SHIFT: 
                isRunning = false;
                if (isMoving) updateMovement(movementDirection);
                break;
                case Keyboard.UP: case Keyboard.W: case Keyboard.Z: //fr
                case Keyboard.DOWN: case Keyboard.S: case Keyboard.SPACE: 
                case Keyboard.E: case Keyboard.R:
                rest();
                break;
                case Keyboard.LEFT: case Keyboard.A: case Keyboard.Q: //fr
                case Keyboard.RIGHT: case Keyboard.D: 
                    currentRotationInc = 0;
                    break;
            }
        }
        
        //-------------------------------- RESIZE
        
        private function onResize(event:Event = null):void {
            _view.width = _stage3DProxy.width = stage.stageWidth;
            _view.height = _stage3DProxy.height = stage.stageHeight;
            _stats.x = stage.stageWidth - _stats.width;
        }
        
        //-------------------------------- NAVIGATION
        
        private function onStageMouseDown(ev:MouseEvent):void {
            _prevMouseX = ev.stageX;
            _prevMouseY = ev.stageY;
            _mouseMove = true;
        }
        
        private function onStageMouseLeave(event:Event):void {
            _mouseMove = false;
        }
        
        private function onStageMouseMove(ev:MouseEvent):void {
            if (_mouseMove) {
                _hoverCtrl.panAngle += (ev.stageX - _prevMouseX);
                _hoverCtrl.tiltAngle += (ev.stageY - _prevMouseY);
            }
            _prevMouseX = ev.stageX;
            _prevMouseY = ev.stageY;
        }
        
        private function onStageMouseWheel(ev:MouseEvent):void {
            _hoverCtrl.distance -= ev.delta * (5*SCALE)
            if (_hoverCtrl.distance < 500*SCALE) {
                if (ev.delta > 0)
                    _cameraHeight += 5*SCALE;
                else
                    _cameraHeight -= 5*SCALE;
            }
            if (_hoverCtrl.distance < 10*SCALE)
                _hoverCtrl.distance = 10*SCALE;
            else if (_hoverCtrl.distance > 1000*SCALE)
                _hoverCtrl.distance = 1000*SCALE;
        }
        
        //-------------------------------- FLASH SIDE
        
        /** Display simple text */
        private function initText():void {
            _text = new TextField();
            _text.defaultTextFormat = new TextFormat("Verdana", 9, 0xAAAAAA);
            _text.x=2;
            _text.width = 300;
            _text.height = 250;
            _text.selectable = false;
            _text.mouseEnabled = true;
            _text.wordWrap = true;
            _text.filters = [new DropShadowFilter(1, 45, 0x0, 1, 0, 0)];
            addChild(_text);
        }
        
        /** final message */
        protected function message():void {
            _text.htmlText = "<b>Human Theatre</b> beta 0.1\n"
            //_text.appendText("Cursor keys / WSAD / ZSQD - move\n");
            //_text.appendText("SHIFT - hold down to run\n");
            _text.appendText("N - random sky\n");
        }
        
        //-------------------------------- LOG DEBUG
        
        /** log for display info */
        private final function log(t:String):void {
            _text.htmlText = t;
        }
        
        //-------------------------------- MATHEMATICS
        
        private static function randomColor():Number {
            return 0xFFFFFF * Math.random();
        }
        
        private static function rand(max:Number = 1, min:Number = 0):Number { 
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }
        
        private static function orbit(H:Number, V:Number, D:Number, extraY:Number=0):Vector3D {
            var p:Vector3D = new Vector3D();
            var phi:Number = radToDeg(H);
            var theta:Number = radToDeg(V);
            p.x = (D * Math.sin(phi) * Math.cos(theta));
            p.z = (D * Math.sin(phi) * Math.sin(theta));
            p.y = (D * Math.cos(phi))+extraY;
            return p;
        }
        
        private static function radToDeg(d:Number):Number {
            return (d * (Math.PI / 180));
        } 
        
    }
}


//-------------------------------------o
//          FLINT PARTICULE            o
//-------------------------------------o

import org.flintparticles.integration.away3d.v4.initializers.A3D4CloneObject;
import org.flintparticles.common.initializers.Lifetime;
import org.flintparticles.threeD.initializers.Position;
import org.flintparticles.threeD.initializers.Velocity;
import org.flintparticles.common.actions.TargetScale;
import org.flintparticles.threeD.actions.RandomDrift;
import org.flintparticles.threeD.emitters.Emitter3D;
import org.flintparticles.threeD.actions.DeathZone;
import org.flintparticles.threeD.actions.Friction;
import org.flintparticles.common.counters.Steady;
import org.flintparticles.threeD.zones.BoxZone;
import org.flintparticles.threeD.actions.Move;
import org.flintparticles.common.actions.Fade;
import org.flintparticles.common.actions.Age;

import away3d.primitives.SphereGeometry;
import away3d.materials.ColorMaterial;
import away3d.entities.Mesh;

import flash.geom.Vector3D;

internal class EmitterSmoke extends Emitter3D
{
    public function EmitterSmoke(O:Object = null)
    {
        counter = new Steady(10);
        // test cloning character 
  //      var sphere:Mesh = O.addAvatar({anim:2, speed:1, hair:false})
        var sphere:Mesh = new Mesh(new SphereGeometry(10), new ColorMaterial(0xffffff, 0.3));
        addInitializer(new Position(new BoxZone(100, 100, 1000, new Vector3D(1000, 0, 0))));
        //addInitializer(new Lifetime(10));
        addInitializer(new Velocity(new BoxZone(200, 20, 200, new Vector3D( -100, 0, 0)))); 
        
        var clone:A3D4CloneObject = new A3D4CloneObject( sphere, true, 400 )
        addInitializer( clone );
        //addAction(new Age());
        addAction(new Move());
        addAction(new Friction(0.9));
        addAction(new Fade(0.7, 1.0));
        addAction(new TargetScale(10));
        addAction(new RandomDrift(50, 10, 50));
        addAction(new DeathZone(new BoxZone(2000, 1000, 2000), true));
    }
}


//-------------------------------------o
//           VECTOR MAPPER             o
//-------------------------------------o

import flash.display.Stage;
import flash.filters.DisplacementMapFilter;
import away3d.textures.BitmapCubeTexture;
import flash.display.DisplayObject;
import flash.filters.ShaderFilter;
import flash.geom.ColorTransform;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.Shader;
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.geom.Point;
    
internal class Mapper extends Sprite {
    private var _shaders:Vector.<Shader>;
    private var _bitmap:Vector.<Bitmap>;
    private var _bitdata:Vector.<BitmapData>;
    private var _skydata:Vector.<BitmapData>;
    private var _sky:BitmapCubeTexture;
    
    //-------------------------------- REFERENCY

    public function get bitdata():Vector.<BitmapData> { return _bitdata; }  
    public function get sky():BitmapCubeTexture { return _sky; }
    
    //-------------------------------- VECTOR SKY
    
    /** create vector sky */
    public function vectorSky(C:Array, quality:uint=8):void {
        var xl:uint = 128 * quality;
        var pinch:uint = xl / 3.6;
        // sky color from bottom to top;
        var color:Array = [brighten(C[0], 50), darken(C[0], 25), darken(C[0], 5), darken(C[1], 0), C[1], C[2], darken(C[2], 25), darken(C[2], 50)];
        var side:BitmapData = new BitmapData(xl, xl, false, color[1]);
        var top:BitmapData = new BitmapData(xl, xl, false, color[6]);
        var floor:BitmapData = new BitmapData(xl, xl, false, color[1]);
        // side
        var matrix:Matrix = new Matrix();
        matrix.createGradientBox(xl, xl, -Math.PI / 2)
        var g:Sprite = new Sprite();
        g.graphics.beginGradientFill('linear', [color[1], color[2], color[3], color[4], color[5], color[6]], [1, 1, 1, 1, 1, 1], [90, 110, 120, 126, 180, 230], matrix);
        g.graphics.drawRect(0, 0, xl, xl);
        g.graphics.endFill();
        var displacement_map:DisplacementMapFilter = new DisplacementMapFilter(pinchMap(xl, xl), new Point(0, 0), 4, 2, 0, pinch, "clamp")
        g.filters = [displacement_map];
        side.draw(g);
        // top
        matrix = new Matrix();
        g.graphics.clear();
        matrix.createGradientBox(xl, xl, 0, 0, 0);
        g.graphics.beginGradientFill('radial', [color[7], color[6]], [1, 1], [0, 255], matrix);
        g.graphics.drawEllipse(0, 0, xl, xl);
        g.graphics.endFill();
        top.draw(g);
        // bottom
        matrix = new Matrix();
        matrix.createGradientBox(xl, xl, 0, 0, 0);
        g.graphics.clear();
        g.graphics.beginGradientFill('radial', [color[0], color[1]], [1, 1], [0, 255], matrix);
        g.graphics.drawEllipse(0, 0, xl, xl);
        g.graphics.endFill();
        floor.draw(g);
        
        _skydata = new Vector.<BitmapData>();
        _skydata.push(side, top, floor);
        if (_sky) _sky.dispose();
        _sky = new BitmapCubeTexture(side, side, top, floor, side, side);
    }
    
    /** add some sphericale distortion */
    private function pinchMap(w:int, h:int):BitmapData {
        var i:int, BCol:Number, GCol:Number;
        var b:BitmapData = new BitmapData(w, h, false, 0x000000)
        var vx:int = w >> 1, vy:int = h >> 1;
        for (var j:int = 0; j < h; j++) {
            for ( i = 0; i < w; i++) {
                BCol = 127 + (i - vx) / (vx) * 127 * (1 - Math.pow((j - vy) / (vy), 2));
                GCol = 127 + (j - vy) / (vy) * 127 * (1 - Math.pow((i - vx) / (vx), 2));
                b.setPixel(i, j, (GCol << 8) | BCol);
            }
        }
        return b;
    }
    
    //-------------------------------- COLORS UTILS
        
    /** brighten color */
    public function brighten(hexColor:Number, percent:Number):Number {
        if (isNaN(percent)) percent = 0;
        if (percent > 100) percent = 100;
        if (percent < 0) percent = 0;
        var factor:Number = percent / 100, rgb:Object = hexToRgb(hexColor);
        rgb.r += (255 - rgb.r) * factor; rgb.b += (255 - rgb.b) * factor; rgb.g += (255 - rgb.g) * factor;
        return rgbToHex(Math.round(rgb.r), Math.round(rgb.g), Math.round(rgb.b));
    }
        
    /** darken color */
    public function darken(hexColor:Number, percent:Number):Number {
        if (isNaN(percent)) percent = 0;
        if (percent > 100) percent = 100;
        if (percent < 0) percent = 0;
        var factor:Number = 1 - (percent / 100), rgb:Object = hexToRgb(hexColor);
        rgb.r *= factor; rgb.b *= factor; rgb.g *= factor;
        return rgbToHex(Math.round(rgb.r), Math.round(rgb.g), Math.round(rgb.b));
    }
        
    /** conversion */
    public function rgbToHex(r:Number, g:Number, b:Number):Number { return (r << 16 | g << 8 | b); }
    public function hexToRgb(hex:Number):Object { return {r: (hex & 0xff0000) >> 16, g: (hex & 0x00ff00) >> 8, b: hex & 0x0000ff}; }
        
    /** apply color to object */
    public function color(o:DisplayObject, c:int=0, a:Number=1):void {
        if (!o) return;
        var nc:ColorTransform = o.transform.colorTransform;
        nc.color = c;
        nc.alphaMultiplier = a;
        if (c == 0) o.transform.colorTransform = new ColorTransform();
        else o.transform.colorTransform = nc;
    }
}


//-------------------------------------o
//           LOADING BITMAP            o
//-------------------------------------o

import flash.display.Sprite;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.system.LoaderContext;

internal class PhotoLoader extends Sprite {
    private var loader:Loader;
    public var content:BitmapData;
    public static const COMPLETE:String = Event.COMPLETE;

    public function PhotoLoader() {
        loader = new Loader();
    }
    public function load(file:String):void {
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, complete, false, 0, true);
        loader.load(new URLRequest(file), new LoaderContext(true));
    }
    private function complete(evt:Event):void {
        loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, complete);
        content = Bitmap(loader.contentLoaderInfo.content).bitmapData;
        dispatchEvent(new Event(PhotoLoader.COMPLETE));
        loader.unload();
        loader = null;
    }

}