<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="800" height="500"
                creationComplete="init()" addedToStage="stage.quality = 'low'" backgroundColor="0x000000"
                color="0xdddddd" fontWeight="bold" viewSourceURL="srcview/index.html">
    <mx:Script>
        <![CDATA[
            import com.adobe.viewsource.ViewSource;
            import com.as3dmod.util.ModConstant;
            import org.papervision3d.objects.primitives.Cylinder;
            import com.as3dmod.plugins.pv3d.LibraryPv3d;
            import com.as3dmod.modifiers.Noise;
            import org.papervision3d.objects.primitives.Plane;
            import org.papervision3d.materials.utils.MaterialsList;
            import org.papervision3d.materials.BitmapMaterial;
            import org.papervision3d.view.stats.StatsView;
            import com.as3dmod.util.Phase;
            import com.as3dmod.modifiers.Cloth;
            import com.as3dmod.ModifierStack;
            import org.papervision3d.lights.PointLight3D;
            import org.papervision3d.objects.DisplayObject3D;
            import org.papervision3d.render.BasicRenderEngine;
            import org.papervision3d.scenes.Scene3D;
            import org.papervision3d.cameras.Camera3D;
            import org.papervision3d.view.Viewport3D;
            
            private var _view : Viewport3D;
            private var _camera : Camera3D;
            private var _scene : Scene3D;
            private var _renderer : BasicRenderEngine;
            private var _flag : DisplayObject3D;
            
            private var _modifierStack : ModifierStack;
            private var _cloth : Cloth;
            
            private var _wind : Number = 2;
            private var _windDirection : Number = 1;
            private var _windVariation : Number = 2;
            
            [Embed(source="../assets/flag.png")]
            private var _flagAsset : Class;
            
            [Embed(source="../assets/wood.jpg")]
            private var _woodAsset : Class;
            
            [Embed(source="../assets/clouds.jpg")]
            private var _background : Class;
            
            public function init() : void
            {
                // add epic clouds
                container.addChild(new _background());
                
                // initialize libraries
                initPV3D();
                initAS3DMod();
                
                container.addChild(new StatsView(_renderer));
                addEventListener(Event.ENTER_FRAME, handleEnterFrame);
                
                ViewSource.addMenuItem(this, "srcview");
            }
            
            private function initPV3D() : void
            {
                var bmp : BitmapData;
                var material : BitmapMaterial;
                var pole : Cylinder;
                
                // create basic scene setup
                _scene = new Scene3D();
                _view = new Viewport3D(800, 600);
                _view.y = -100;
                _renderer = new BasicRenderEngine();
                
                _camera = new Camera3D();
                
                // create the flagpole
                bmp = new _woodAsset().bitmapData;
                material = new BitmapMaterial(bmp);
                pole = new Cylinder(material, 10, 1000, 4, 1);
                pole.x = -260;
                pole.z = 5;
                pole.y = -280;
                _scene.addChild(pole);
                
                // create the flag
                bmp = new _flagAsset().bitmapData;
                material = new BitmapMaterial(bmp);
                _flag = new Plane(material, 500, 400, 15, 20);
                _flag.material.doubleSided = true;
                _scene.addChild(_flag);
                
                _camera.target = _flag;
                
                container.addChild(_view);
            }
            
            private function initAS3DMod() : void
            {
                // create the modifier stack and assing it to the flag
                _modifierStack = new ModifierStack(new LibraryPv3d(), _flag);
                
                // optional code to create a bit more randomness:
                // var noise : Noise = new Noise(20);
                // noise.constraintAxes(ModConstant.X | ModConstant.Y);
                // _modifierStack.addModifier(noise);
                // _modifierStack.collapse();
                
                // create the cloth modifier and add it to the stack
                _cloth = new Cloth();
                _modifierStack.addModifier(_cloth);
                
                // sets the left side of the flag as immobile
                _cloth.lockXMin(0);
                
                // add gravity
                _cloth.forceY = -.3;
            }
            
            private function handleEnterFrame(event : Event) : void
            {
                var halfW : Number = stage.stageWidth*.5,
                    halfH : Number = stage.stageHeight*.5;
                var cameraAngle : Number = (0.1+mouseX/halfW-halfW)*1.3;
                
                // set external forces to mimick wind
                _cloth.forceX = Math.sin(_windDirection)*_wind-Math.random()*_windVariation;
                _cloth.forceZ = Math.cos(_windDirection)*_wind-Math.random()*_windVariation;
                
                // applies the modifier and updates the cloth simulation
                _modifierStack.apply();
                
                // update camera position relative to mouse position
                _camera.x = Math.sin(cameraAngle)*500;
                _camera.z = Math.cos(cameraAngle)*500;
                _camera.y = Math.sin(mouseY/halfH-halfH)*300;
                
                // render the scene
                _renderer.renderScene(_scene, _camera, _view);
            }
        ]]>
    </mx:Script>
    <mx:UIComponent id="container" />
    <mx:VBox bottom="30">
        <mx:HBox>
            <mx:Text text="Gravity: " width="75" />
            <mx:HSlider id="gravitySlider" value=".3" minimum="0" maximum="1" change="{_cloth.forceY = -gravitySlider.value}" liveDragging="true" />
            <mx:Text text="Air friction: " width="75" />
            <mx:HSlider id="frictionSlider" value="0" minimum="0" maximum="10" change="{_cloth.friction = frictionSlider.value}" liveDragging="true" />
            <mx:Text text="Rigidity: " width="75" />
            <mx:HSlider id="rigiditySlider" value="1" minimum="0.1" maximum="1" change="{_cloth.rigidity = rigiditySlider.value}" liveDragging="true" />
        </mx:HBox>
        <mx:HBox>
            <mx:Text text="Wind speed: " width="75" />
            <mx:HSlider id="windSpeedSlider" value="2" minimum="0" maximum="5" change="{_wind = windSpeedSlider.value}" liveDragging="true" />
            <mx:Text text="Wind direction: " width="75" />
            <mx:HSlider id="windDirectionSlider" value=".3" minimum="{-Math.PI}" maximum="{Math.PI}" change="{_windDirection = windDirectionSlider.value}" liveDragging="true" />
            <mx:Text text="Wind variation: " width="75" />
            <mx:HSlider id="windVariationSlider" value="2" minimum="{0}" maximum="{windSpeedSlider.value*2}" change="{_windVariation = windVariationSlider.value}" liveDragging="true" />
        </mx:HBox>
    </mx:VBox>
</mx:Application>