|
@@ -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();
|
|
|
}
|
|
|
}
|
|
|
}
|