// Demo for the PaperKing Contest Augustus 2008
// Release date: 18-8-2008
// Made by Ringo from FlashBookmarks (http://www.flashbookmarks.com)
// PV3D GreatWhite rev. 691
// Caurina Tweener - http://code.google.com/p/tweener/
//
// Video and mix by Karl Moestl http://www.karlmoestl.com/ & http://www.myspace.com/karlmoestl
//
// Special thanks to JMD for providing the 3D model and Dara for setting up the bipped
// Used motion capture files and created a motion flow on the robot
//
// Usefull code is the cubeSkySphere, which is a skybox as a Cube with 6 sides and it can be transformed to a Sphere
//
// TODO make it dynamic based on the music (bpm and genre), interaction with the user

package
{
    // Imports
    import caurina.transitions.Tweener;
    
    import fl.video.VideoEvent;
    
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageQuality;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.media.SoundTransform;
    import flash.media.Video;
    import flash.net.NetConnection;
    import flash.net.NetStream;
    
    import nl.si.pv3d.objects.CubeSkySphere;
    
    import org.papervision3d.cameras.Camera3D;
    import org.papervision3d.events.FileLoadEvent;
    import org.papervision3d.lights.PointLight3D;
    import org.papervision3d.materials.BitmapFileMaterial;
    import org.papervision3d.materials.BitmapMaterial;
    import org.papervision3d.materials.MovieMaterial;
    import org.papervision3d.materials.shadematerials.GouraudMaterial;
    import org.papervision3d.materials.utils.MaterialsList;
    import org.papervision3d.objects.parsers.DAE;
    import org.papervision3d.objects.primitives.Cube;
    import org.papervision3d.objects.primitives.Plane;
    import org.papervision3d.render.BasicRenderEngine;
    import org.papervision3d.scenes.Scene3D;
    import org.papervision3d.view.Viewport3D;
    import org.papervision3d.view.layer.ViewportLayer;
    
    [SWF(backgroundColor="0x000000")]
    public class DanceKingPV3D extends Sprite
    {
        // PV3D vars
        private var viewport:Viewport3D;  
        private var scene:Scene3D;  
        private var camera:Camera3D; 
        private var renderer:BasicRenderEngine;
        private var lightpoint:PointLight3D;
        private var angle:int = 0;

        // DAE models vars        
        private var danceKing1:DAE;
        private var danceKing2:DAE;
        private var mlDanceKing:MaterialsList;
        
        //SkyBox vars
        private var skyBoxSphere:CubeSkySphere;
        private var skyBoxSphereSize:int = 20000;
        private var skyBoxSphereSegments:int = 6;

        // Video vars
        private var connection : NetConnection;
        private var stream : NetStream;
        private var video : Video;
        private var videoWidth:int = 640;
        private var videoHeight:int = 480;
        private var videoST:SoundTransform;
        private var playvideo:Boolean;

        private var videoPlane:Plane;
        private var videoMaterial:BitmapMaterial;
        private var spectrumPlane:Plane;
        private var ground:Plane;

        // Viewportlayers vars
        private var vpl0:ViewportLayer;
        private var vpl1:ViewportLayer;
        private var vpl2:ViewportLayer;
        private var vpl3:ViewportLayer;
        private var vpl4:ViewportLayer;
        private var vpl5:ViewportLayer;
        
        // DanceKing model
        [Embed(source="assets/geometry/DanceKingAnimated.dae", mimeType="application/octet-stream")]
        private var DanceKing:Class;

        [Embed(source="assets/grx/lpking.png")]
        public var GroundMATERIAL:Class; 

        
        public function DanceKingPV3D()
        {
            init();
        }         

        private function init():void
        {
            setupStage();
            setupPV3D();
            setup3DObjects();
        }   


        //============================================
        //SETUP STAGE
        //============================================
        private function setupStage():void
        {        
            stage.quality = StageQuality.MEDIUM;
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.frameRate = 30;
        }

        
        //============================================
        //SETUP PV3D
        //============================================
        private function setupPV3D():void
        {
            viewport = new Viewport3D(stage.stageWidth,stage.stageHeight, true, true, true, true);
            addChild(viewport);
            renderer = new BasicRenderEngine(); 
            scene = new Scene3D();  
            camera = new Camera3D(60,10,500000,true,true);
            camera.focus = 100;
            camera.zoom = 10;
            camera.z = 0;
            camera.z = -1000;
            lightpoint = new PointLight3D(false,true);
            lightpoint.z = -1000;
        }


        //============================================
        // SETUP 3D OBJECTS
        //============================================
        private function setup3DObjects():void
        {
                // Create a SkyBox, which is a cube with 6 sides and is then transformed to a sphere
                createSkyBox();

                // Setup Video plane
                videoMaterial = new BitmapMaterial(new BitmapData(320,240,false));
                videoMaterial.doubleSided=false;
                videoMaterial.smooth = true;
                videoPlane = new Plane( videoMaterial, videoWidth, videoHeight, 1, 1);
                videoPlane.z = 1000;
                videoPlane.y = 400;
                scene.addChild(videoPlane);
                   vpl3 = viewport.getChildLayer(videoPlane);
                vpl3.layerIndex = 3;
                vpl3.alpha = 0.3

                // Setup ground with videoMaterial
                var groundMat:BitmapMaterial = new BitmapMaterial( Bitmap( new GroundMATERIAL() ).bitmapData );
                groundMat.smooth = true;
                ground = new Plane(groundMat,2241,2241,16,16)
                //ground = new Plane(videoMaterial,2500,2500,1,1)
                ground.rotationX = 90;
                ground.y = -265;
                ground.z = 1400;
                scene.addChild(ground);
                vpl1 = viewport.getChildLayer(ground);
                vpl1.layerIndex = 1;
                vpl1.alpha = 0.3;    
                
                // Setup soundspectrum
                var displaySpectrum:MovieClip = new Simplespectrum();
                addChild(displaySpectrum);
                var spectrumMaterial:MovieMaterial = new MovieMaterial(displaySpectrum, true, true,false);
                spectrumMaterial.smooth= true;
                spectrumMaterial.opposite = true;
                spectrumPlane = new Plane( spectrumMaterial, displaySpectrum.width, displaySpectrum.height, 1, 1);
                spectrumPlane.z = 1100;
                spectrumPlane.y = 762;
                spectrumPlane.rotationX=180;
                scene.addChild(spectrumPlane);
                   vpl2 = viewport.getChildLayer(spectrumPlane);
                vpl2.layerIndex = 2;
                vpl2.alpha = 0.3

                //setup dancekings
                mlDanceKing = new MaterialsList({BasicMtrl: videoMaterial});
            
                //create the DAE and load the mesh
                danceKing1 = new DAE(false,"danceKing1");
                danceKing1.load(XML(new DanceKing()),mlDanceKing);

                //Creates the DAE object and loads the mesh
                danceKing2 = new DAE(false,"danceKing2");
                danceKing2.addEventListener(FileLoadEvent.LOAD_COMPLETE, loadCompleteDAE);
                danceKing2.addEventListener(FileLoadEvent.ANIMATIONS_COMPLETE,loadCompleteAnimationsDAE);
                danceKing2.load(XML(new DanceKing()),mlDanceKing);
        }

        
        //============================================
        // LOAD COMPLETE DAE
        //============================================
        private function loadCompleteDAE(e:FileLoadEvent):void
        {
            var scaleDae:int = 200;

            danceKing1.x = -200;
            danceKing1.y = -266;
            danceKing1.z = 2200;

            danceKing1.scale = scaleDae;
            scene.addChild(danceKing1)
               vpl4 = viewport.getChildLayer(danceKing1);
            vpl4.layerIndex = 4;
            vpl4.alpha = 0.3

            danceKing2.scale = scaleDae;
            danceKing2.x = 200;
            danceKing2.y = -266;
            danceKing2.z = 600;
            danceKing2.rotationY=180;
            scene.addChild(danceKing2);
               vpl5 = viewport.getChildLayer(danceKing2);
            vpl5.layerIndex = 5;
            vpl5.alpha = 0.3    

            // Setup eventlisteners
            addEventListeners();
        } 


        //============================================
        // LOAD COMPLETE ANIMATIONS DAE
        //============================================        
        private function loadCompleteAnimationsDAE(e:FileLoadEvent):void
        {
            // Start the animations
            danceKing1.play();
            danceKing2.play();

            // Tween the alpha on the viewportlayers 
            Tweener.addTween(vpl0, {alpha:1, time:2, transition:"linear"});
            Tweener.addTween(vpl1, {alpha:.7, time:2, transition:"linear"});
            Tweener.addTween(vpl2, {alpha:1, time:2, transition:"linear"});
            Tweener.addTween(vpl3, {alpha:1, time:2, transition:"linear"});
            Tweener.addTween(vpl4, {alpha:1, time:2, transition:"linear"});
            Tweener.addTween(vpl5, {alpha:1, time:2, transition:"linear"});
        }


        //============================================
        //SETUP VIDEO
        //============================================
        private function setupVideo():void
        {
            connection = new NetConnection();
            connection.connect(null);
            stream = new NetStream(connection);
            stream.bufferTime = 5;
            stream.client = new Object();  //prevents error message, not catching onMetaData
            videoWidth = 320;
            videoHeight = 240;
            video = new Video(videoWidth, videoHeight);
        }

        
        //============================================
        // START VIDEO
        //============================================
        private function startVideo(videoSource:String):void
        {
            stream.play(videoSource); // video to play
            video.attachNetStream(stream);
            playvideo=true;
            // Set volume to max.
            videoST = new SoundTransform();
            videoST.volume = 1;
            stream.soundTransform = videoST;
            // End video
            stream.addEventListener(VideoEvent.COMPLETE, completeListenerVideo );
        }
    
        private function completeListenerVideo( e:VideoEvent ):void
        {
            Tweener.addTween(vpl0, {alpha:0, time:1, transition:"linear"});
            Tweener.addTween(vpl1, {alpha:0, time:1, transition:"linear"});
            Tweener.addTween(vpl2, {alpha:0, time:1, transition:"linear"});
            Tweener.addTween(vpl3, {alpha:0, time:1, transition:"linear"});
            Tweener.addTween(vpl4, {alpha:0, time:1, transition:"linear"});
            Tweener.addTween(vpl5, {alpha:0, time:1, transition:"linear"});
            trace("THE END");
        }


        //============================================
        // CREATE THE SKYBOX CUBE TO SPHERE
        //============================================
        private function createSkyBox():void
        {
            // Load up cubemap textures
            var sbDown:Bitmap               = new Resources.SkyboxDown as Bitmap;
            var sbDownBM:BitmapMaterial     = new BitmapMaterial(sbDown.bitmapData);
            var sbEast:Bitmap                 = new Resources.SkyboxEast as Bitmap;
            var sbEastBM:BitmapMaterial     = new BitmapMaterial(sbEast.bitmapData);
            var sbNorth:Bitmap                = new Resources.SkyboxNorth as Bitmap;
            var sbNorthBM:BitmapMaterial    = new BitmapMaterial(sbNorth.bitmapData);
            var sbSouth:Bitmap               = new Resources.SkyboxSouth as Bitmap;
            var sbSouthBM:BitmapMaterial     = new BitmapMaterial(sbSouth.bitmapData);
            var sbUp:Bitmap                   = new Resources.SkyboxUp as Bitmap;
            var sbUpBM:BitmapMaterial         = new BitmapMaterial(sbUp.bitmapData);
            var sbWest:Bitmap               = new Resources.SkyboxWest  as Bitmap;
            var sbWestBM:BitmapMaterial     = new BitmapMaterial(sbWest.bitmapData);

            // Material list for the CubetoSphere skybox
            var ml:MaterialsList = new MaterialsList();
            ml.addMaterial(sbWestBM,"left");
            ml.addMaterial(sbEastBM,"right");
            ml.addMaterial(sbUpBM,"top");
            ml.addMaterial(sbDownBM,"bottom");
            ml.addMaterial(sbNorthBM,"front");
            ml.addMaterial(sbSouthBM,"back");

            // Flip the faces so the textures are inside
            var insideFaces  :int = Cube.ALL;
            var excludeFaces :int = Cube.NONE;
            
            skyBoxSphere = new CubeSkySphere(ml, skyBoxSphereSize, skyBoxSphereSize, skyBoxSphereSize, skyBoxSphereSegments, skyBoxSphereSegments, skyBoxSphereSegments, insideFaces, excludeFaces);
            skyBoxSphere.transformCubeToSphere(false);
            scene.addChild(skyBoxSphere);

            // Setup viewportlayer
            vpl0 = viewport.getChildLayer(skyBoxSphere);
            vpl0.layerIndex = 0;
            vpl0.alpha = 0.3;    
        }


        //============================================
        // SETUP Eventlisteners
        //============================================        
        private function addEventListeners():void
        {
            // Setup and start the video
               setupVideo();
               // start streaming video 
               startVideo("assets/video/KarlMoestlKungFuFigh.flv");
            // Setup enter_frame tick
            addEventListener(Event.ENTER_FRAME, tick);
        }


        //============================================
        // SETUP TICK
        //============================================        
        private function tick(e:Event):void
        {
            videoPlane.material.bitmap.draw(video)
            skyBoxSphere.yaw(-4);
            ground.roll(-12);    

            //camera movement
            angle++;
            camera.x     = -Math.cos(this.angle * 3.14 / 60) * 500;
            camera.z     = (Math.sin(this.angle * 3.14 / 60) * 400) - 1000;
            camera.y     = (Math.sin(this.angle * 0.8 * 3.14 / 180) + 1.525) * 100;
            camera.lookAt(videoPlane);
            renderer.renderScene(scene, camera, viewport);
        }

    }
}    // EOF