package {
    
    /**
     * 
     *     Auteur: Vincent Helwig
     *     Date: 30.09.2008
     *     Website: http://www.tsoin.com
     *     Description: Démo Alternativa3D Box / Sphere / Plane / Cone
     *                         Gestion Filaire / Texture
     *                         Smooth
     * 
     **/
     
    import alternativa.engine3d.controllers.CameraController;
    import alternativa.engine3d.core.Camera3D;
    import alternativa.engine3d.core.Mesh;
    import alternativa.engine3d.core.Object3D;
    import alternativa.engine3d.core.Scene3D;
    import alternativa.engine3d.display.View;
    import alternativa.engine3d.materials.TextureMaterial;
    import alternativa.engine3d.materials.WireMaterial;
    import alternativa.engine3d.primitives.Box;
    import alternativa.engine3d.primitives.Cone;
    import alternativa.engine3d.primitives.Plane;
    import alternativa.engine3d.primitives.Sphere;
    import alternativa.types.Texture;
    import alternativa.utils.FPS;
    
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.utils.getTimer;
    
    [SWF(backgroundColor="#000000", frameRate="100", width="600", height="400")]

    public class Alternativa3D_004 extends Sprite    {
        
        private var scene:Scene3D;
        private var view:View;
        private var camera:Camera3D;
        private var cameraController:CameraController;
        private var currentPrimitive:Mesh;
        private var box:Box;
        private var sphere:Sphere;
        private var cone:Cone;
        private var plane:Plane;
        private var _textFaces:TextField;
        private var _tempsCreation:uint;

        private var _texture:Boolean = false;
        private var _smoothTexture:Boolean = false;
        private var _numSegments:uint = 3;
        private var currentPrimitiveName:String = "box";
        
        // Nombre de faces minimum pour chaque Object 3D
        private static const MIN_FACES_BOX:uint = 3;
        private static const MIN_FACES_SPHERE:uint = 8;
        private static const MIN_FACES_PLANE:uint = 3;
        private static const MIN_FACES_CONE:uint = 6;
        // Coordonnée Z maximum de la camera
        private static const MAX_Z:int = -200;
        private static const TEXT_EXPLICATION:String = "" + 
                "Utiliser la molette pour modifier la coordonée z de la camera<br>" + 
                "Action du clavier : <br>" + 
                " + / - : Augmente / Diminue le nombre de segments<br>" + 
                " T / F : Mode texture / Mode filaire<br>" + 
                " L : Active/Désactive le lissage de la texture<br>" + 
                " C / S / P / B : Forme Cone / Sphere / Plane / Box<br><br>";                
        [Embed(source="AdobeFlash9.png")] private static const bmpWall:Class;
        private static const wallTexture:Texture = new Texture(new bmpWall().bitmapData, "logo");
        
        public function Alternativa3D_004()    {
            addEventListener(Event.ADDED_TO_STAGE, init);
            
            var __textFormat:TextFormat = new TextFormat();
            __textFormat.font = "Arial";
            __textFormat.size = 9;
            
            _textFaces = new TextField();
            _textFaces.selectable = false;
            _textFaces.multiline = true
            _textFaces.width = stage.stageWidth;
            _textFaces.height = stage.stageHeight;
            _textFaces.defaultTextFormat = __textFormat;
            _textFaces.textColor = 0x999999;
            addChild( _textFaces );
        }

        public function init(e:Event): void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            
            setupScene();
            
            numSegments = _numSegments;

            stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
            stage.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
        }
        
        /**
         * 
         *     Instanciation du moteur 3D Alternativa
         * 
         **/
        
        private function setupScene():void {
            
            scene = new Scene3D();
            scene.root = new Object3D();
            
            camera = new Camera3D();
            camera.x = 0;
            camera.y = 0;
            camera.z = -300;
            camera.zoom = 10;
            camera.fov = 1.5;
            scene.root.addChild(camera);
            
            view = new View();
            view.width = 600;
            view.height = 400;
            addChild(view);
            view.camera = camera;

            cameraController = new CameraController(stage);
            cameraController.camera = camera;
            
            createPrimitive();
            
            FPS.init(stage);
        }
        
        /**
         * 
         *     Création de la primivite suivant la valeur de la variable currentPrimitiveName
         * 
         **/
        
        private function createPrimitive():void {
            var __t:Number = getTimer();
            switch ( currentPrimitiveName ) {
                default :
                case "box" : currentPrimitive = createBox(); break;
                case "sphere" : currentPrimitive = createSphere(); break;
                case "plane" : currentPrimitive = createPlane(); break;
                case "cone" :     currentPrimitive = createCone(); break;
            }
            _tempsCreation = getTimer() - __t;
             numSegments = _numSegments;
             if ( _texture ) { currentPrimitive.cloneMaterialToAllSurfaces( new TextureMaterial(wallTexture, 1.0, true, _smoothTexture) );}
            else { currentPrimitive.cloneMaterialToAllSurfaces(new WireMaterial(1, 0x789789)); }
            scene.root.addChild( currentPrimitive );
            // On met à jour en fonction de la position de la souris
            onMouseMove();
        }
        
        /**
         * 
         *     Création d'une box
         * 
         **/
        
        private function createBox():Box {
            box = new Box(100, 100, 100, _numSegments, _numSegments, _numSegments);
            return box;
        }
        
        /**
         * 
         *     Création d'une sphere
         * 
         **/
        
        private function createSphere():Sphere {
            sphere = new Sphere(100, _numSegments , _numSegments, false, true);
            return sphere;
        }
        
        /**
         * 
         *     Création d'un plane
         * 
         **/
        
        private function createPlane():Plane {
            plane = new Plane(100, 100, _numSegments, _numSegments);
            return plane;
        }
        
        /**
         * 
         *     Création d'un cône
         * 
         **/
        private function createCone():Cone {
            cone = new Cone(100, 100, 0, _numSegments, _numSegments, false, true);
            return cone;
        }
        
        /**
         * 
         *     Au mouvement de la souris, on met à jour l'Object 3D en fonction de la position de la souris
         * 
         **/
        private function onMouseMove(event:Event = null):void {
            currentPrimitive.rotationX = Math.PI * ( ( stage.mouseY * 360 ) / stage.stageHeight - 90 ) / 180;
            currentPrimitive.rotationY = Math.PI * ( ( stage.mouseX * 360 ) / stage.stageWidth - 90 ) / 180;
        }
        
        /**
         * 
         *     Rendu du moteur Alternativa3D
         * 
         **/
        private function onEnterFrame(event:Event):void {
                cameraController.processInput();
                scene.calculate();
        }
        
        /**
         * 
         *     Action sur une touche du clavier
         *     Suivant la touche :
         *         - Mise à jour du nombre de segments de l'Object 3D affichée
         *         - Création d'un nouvel Object 3D
         * 
         **/
        private function onKeyDown(event:KeyboardEvent):void {
            var __change:Boolean = true;
            switch ( event.keyCode ) {
                case 107 : // +
                case 187 :// Pavé numérique et "normal"
                    numSegments = _numSegments+1;
                    break;
                case 109 : // - 
                case 54 :    // Pavé  numérique et "normal"
                    if ( _numSegments != 3 ) { numSegments = _numSegments-1; }
                    break;
                case 83 : // Touche S
                    currentPrimitiveName = "sphere";
                    if ( _numSegments < MIN_FACES_SPHERE ) numSegments = MIN_FACES_SPHERE;
                    break;
                case 66 : // Touche B
                    currentPrimitiveName = "box";
                    if ( _numSegments < MIN_FACES_BOX ) numSegments = MIN_FACES_BOX;
                    break;
                case 80 : // Touche P
                    currentPrimitiveName = "plane";
                    if ( _numSegments < MIN_FACES_PLANE ) numSegments = MIN_FACES_PLANE;
                    break;
                case 67 : // Touche C
                    currentPrimitiveName = "cone";
                    if ( _numSegments < MIN_FACES_CONE ) numSegments = MIN_FACES_CONE;
                    break;
                 case 70 : // Touche T
                     _texture = false;
                     break;
                 case 84 : // Touche M
                     _texture = true;
                     break;
                 case 76 : // Touche L
                     _smoothTexture = !_smoothTexture;
                     break;
                default : // Si aucune touche ne correspond à celle qu'on écoute, on passe la variable __change false
                __change = false;
                trace(event.keyCode);
            }
            // Si la touche tapée correspond à une touche écouté, on met à jour le moteur 3D
            if (__change) {
                if ( currentPrimitive.parent != null) { scene.root.removeChild( currentPrimitive ); }
                createPrimitive();
            }
        }
        
        /**
         *
         *     Action de la molette de la souris
         *      On modifie la coordonnée z de la camera
         * 
         **/
        private function onMouseWheel(event:MouseEvent):void {
            camera.z += event.delta * 10;
            if ( camera.z > MAX_Z) camera.z = MAX_Z;
            numSegments = _numSegments;
        }
        
        /**
         * 
         *     Setter du nombre de segments
         *     Mise à jour le texte
         * 
         **/
        private function set numSegments(nb:uint):void {
            _numSegments = nb;
            _textFaces.htmlText = TEXT_EXPLICATION + "<b>SegmentsH && segmentsW = </b>" + _numSegments.toString();
            if ( camera != null) { 
                // _textFaces.htmlText += "<b>Nb faces : </b>" + currentPrimitive.faces.length; 
                _textFaces.htmlText += "<b>Nb vertices : </b>" + currentPrimitive.vertices.length; 
            }
           _textFaces.htmlText += "<b>Temps création object3D : </b>" + _tempsCreation + " ms";
           _textFaces.htmlText += "<b>Lissage texture : </b>" + _smoothTexture;
        }
        
    }
}