ソースを参照

gizmo manager

Trevor Baron 7 年 前
コミット
2f83b9a059
1 ファイル変更122 行追加45 行削除
  1. 122 45
      src/Gizmos/babylon.gizmoManager.ts

+ 122 - 45
src/Gizmos/babylon.gizmoManager.ts

@@ -3,80 +3,157 @@ module BABYLON {
      * Helps setup gizmo's in the scene to rotate/scale/position meshes
      */
     export class GizmoManager implements IDisposable{
-
+        private _gizmoSet:{positionGizmo: Nullable<PositionGizmo>, rotationGizmo: Nullable<RotationGizmo>, scaleGizmo: Nullable<ScaleGizmo>, boundingBoxGizmo: Nullable<BoundingBoxGizmo>};
         private _gizmoLayer:UtilityLayerRenderer;
-        // Set of gizmos that are currently in the scene for each mesh
-        private _gizmoSet:{[meshID: string]: {positionGizmo: PositionGizmo, rotationGizmo: RotationGizmo}} = {}
         private _pointerObserver:Nullable<Observer<PointerInfo>> = null;
+        private _attachedMesh:Nullable<AbstractMesh> = null;
+        private _boundingBoxColor = BABYLON.Color3.FromHexString("#0984e3");
+        private _boundingBoxUtilLayer:Nullable<UtilityLayerRenderer> = null;
+        /**
+         * Array of meshes which will have the gizmo attached when a pointer selected them. If null, all meshes are attachable. (Default: null)
+         */
+        public attachableMeshes:Nullable<Array<AbstractMesh>> = null;
+        /**
+         * If pointer events should perform attaching/detaching a gizmo, if false this can be done manually via attachToMesh. (Default: true)
+         */
+        public usePointerToAttachGizmos = true;
 
         /**
          * Instatiates a gizmo manager
          * @param scene the scene to overlay the gizmos on top of
-         * @param options If only a single gizmo should exist at one time
          */
-        constructor(private scene:Scene, options?:{singleGizmo?:boolean}){
-            this._gizmoLayer = new UtilityLayerRenderer(scene);
-
-            // Options parsing
-            if(!options){
-                options = {}
-            }
-            if(options.singleGizmo === undefined){
-                options.singleGizmo = true;
-            }
+        constructor(private scene:Scene){
+            this._gizmoSet = {positionGizmo: null, rotationGizmo: null, scaleGizmo: null, boundingBoxGizmo: null};
 
             // Instatiate/dispose gizmos based on pointer actions
             this._pointerObserver = scene.onPointerObservable.add((pointerInfo, state)=>{
+                if(!this.usePointerToAttachGizmos){
+                    return;
+                }
                 if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERDOWN){
                     if(pointerInfo.pickInfo && pointerInfo.pickInfo.pickedMesh){
-                        if(!this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId]){
-                            if(options!.singleGizmo){
-                                this._clearGizmos();
-                            }                            
-                            // Enable gizmo when mesh is selected
-                            this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId] = {positionGizmo: new PositionGizmo(this._gizmoLayer), rotationGizmo: new RotationGizmo(this._gizmoLayer)}
-                            this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId].positionGizmo.attachedMesh = pointerInfo.pickInfo.pickedMesh;
-                            this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId].rotationGizmo.attachedMesh = pointerInfo.pickInfo.pickedMesh;
-                        }else{
-                            if(!options!.singleGizmo){
-                                // Disable gizmo when clicked again
-                                this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId].positionGizmo.dispose();
-                                this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId].rotationGizmo.dispose();
-                                delete this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId];
+                        var node:Nullable<Node> = pointerInfo.pickInfo.pickedMesh;
+                        if(this.attachableMeshes == null){
+                            // Attach to the most parent node
+                            while(node && node.parent != null){
+                                node = node.parent;
                             }
-                        }
-                    }else {
-                        if(options!.singleGizmo){
-                            // Disable gizmo when clicked away
-                            if(pointerInfo.pickInfo && pointerInfo.pickInfo.ray){
-                                var gizmoPick = this._gizmoLayer.utilityLayerScene.pickWithRay(pointerInfo.pickInfo.ray);
-                                if(gizmoPick && !gizmoPick.hit){
-                                    this._clearGizmos();
+                        }else{
+                            // Attach to the parent node that is an attachableMesh
+                            var found = false;
+                            this.attachableMeshes.forEach((mesh)=>{
+                                if(node && (node == mesh || node.isDescendantOf(mesh))){
+                                    node = mesh;
+                                    found = true;
                                 }
+                            })
+                            if(!found){
+                                node = null;
                             }
                         }
+                        if(node instanceof AbstractMesh){
+                            this.attachToMesh(node);
+                        }
+                    }else{
+                        this.attachToMesh(null);
                     }
                 }
             })
         }
 
         /**
+         * Attaches a set of gizmos to the specified mesh
+         * @param mesh The mesh the gizmo's should be attached to
+         */
+        public attachToMesh(mesh:Nullable<AbstractMesh>){
+            this._attachedMesh = mesh;
+            for(var key in this._gizmoSet){
+                var gizmo = <Nullable<Gizmo>>((<any>this._gizmoSet)[key]);
+                if(gizmo){
+                    gizmo.attachedMesh = mesh;
+                }
+            }
+        }
+
+        /**
+         * If the position gizmo is enabled
+         */
+        public set positionGizmoEnabled(value:boolean){
+            if(value){
+                this._gizmoSet.positionGizmo = this._gizmoSet.positionGizmo || new PositionGizmo();
+                this._gizmoSet.positionGizmo.updateGizmoRotationToMatchAttachedMesh = false;
+                this._gizmoSet.positionGizmo.attachedMesh = this._attachedMesh;
+            }else if(this._gizmoSet.positionGizmo){
+                this._gizmoSet.positionGizmo.dispose();
+                this._gizmoSet.positionGizmo = null;
+            }
+        }
+        public get positionGizmoEnabled():boolean{
+            return this._gizmoSet.positionGizmo != null;
+        }
+        /**
+         * If the rotation gizmo is enabled
+         */
+        public set rotationGizmoEnabled(value:boolean){
+            if(value){
+                this._gizmoSet.rotationGizmo = this._gizmoSet.rotationGizmo || new RotationGizmo();
+                this._gizmoSet.rotationGizmo.updateGizmoRotationToMatchAttachedMesh = false;
+                this._gizmoSet.rotationGizmo.attachedMesh = this._attachedMesh;
+            }else if(this._gizmoSet.rotationGizmo){
+                this._gizmoSet.rotationGizmo.dispose();
+                this._gizmoSet.rotationGizmo = null;
+            }
+        }
+        public get rotationGizmoEnabled():boolean{
+            return this._gizmoSet.rotationGizmo != null;
+        }
+        /**
+         * If the scale gizmo is enabled
+         */
+        public set scaleGizmoEnabled(value:boolean){
+            if(value){
+                this._gizmoSet.scaleGizmo = this._gizmoSet.scaleGizmo || new ScaleGizmo();
+                this._gizmoSet.scaleGizmo.attachedMesh = this._attachedMesh;
+            }else if(this._gizmoSet.scaleGizmo){
+                this._gizmoSet.scaleGizmo.dispose();
+                this._gizmoSet.scaleGizmo = null;
+            }
+        }
+        public get scaleGizmoEnabled():boolean{
+            return this._gizmoSet.scaleGizmo != null;
+        }
+        /**
+         * If the boundingBox gizmo is enabled
+         */
+        public set boundingBoxGizmoEnabled(value:boolean){
+            if(value){
+                if(!this._boundingBoxUtilLayer){
+                    this._boundingBoxUtilLayer = new BABYLON.UtilityLayerRenderer(this.scene);
+                    this._boundingBoxUtilLayer.utilityLayerScene.autoClearDepthAndStencil = false;
+                }
+                this._gizmoSet.boundingBoxGizmo = this._gizmoSet.boundingBoxGizmo || new BoundingBoxGizmo(this._boundingBoxColor, this._boundingBoxUtilLayer);
+                this._gizmoSet.boundingBoxGizmo.attachedMesh = this._attachedMesh;
+            }else if(this._gizmoSet.boundingBoxGizmo){
+                this._gizmoSet.boundingBoxGizmo.dispose();
+                this._gizmoSet.boundingBoxGizmo = null;
+            }
+        }
+        public get boundingBoxGizmoEnabled():boolean{
+            return this._gizmoSet.boundingBoxGizmo != null;
+        }
+
+        /**
          * Disposes of the gizmo manager
          */
         public dispose(){
             this.scene.onPointerObservable.remove(this._pointerObserver);
-            this._clearGizmos();
-            this._gizmoLayer.dispose();
-        }
-
-        private _clearGizmos(){
             for(var key in this._gizmoSet){
-                if(this._gizmoSet.hasOwnProperty(key)){
-                    this._gizmoSet[key].positionGizmo.dispose();
-                    this._gizmoSet[key].rotationGizmo.dispose();
-                    delete this._gizmoSet[key];
+                var gizmo = <Nullable<Gizmo>>((<any>this._gizmoSet)[key]);
+                if(gizmo){
+                    gizmo.dispose();
                 }
             }
+            this._gizmoLayer.dispose();
         }
     }
 }