sceneTreeItemComponent.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import { Nullable } from "babylonjs/types";
  2. import { Observer, Observable } from "babylonjs/Misc/observable";
  3. import { PointerInfo, PointerEventTypes } from "babylonjs/Events/pointerEvents";
  4. import { IExplorerExtensibilityGroup } from "babylonjs/Debug/debugLayer";
  5. import { GizmoManager } from "babylonjs/Gizmos/gizmoManager";
  6. import { Scene } from "babylonjs/scene";
  7. import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
  8. import { faSyncAlt, faImage, faCrosshairs, faArrowsAlt, faCompress, faRedoAlt } from '@fortawesome/free-solid-svg-icons';
  9. import { ExtensionsComponent } from "../extensionsComponent";
  10. import * as React from "react";
  11. import { GlobalState } from "../../globalState";
  12. import { UtilityLayerRenderer } from 'babylonjs';
  13. interface ISceneTreeItemComponentProps {
  14. scene: Scene;
  15. onRefresh: () => void;
  16. selectedEntity?: any;
  17. extensibilityGroups?: IExplorerExtensibilityGroup[];
  18. onSelectionChangedObservable?: Observable<any>;
  19. globalState: GlobalState;
  20. }
  21. export class SceneTreeItemComponent extends React.Component<ISceneTreeItemComponentProps, { isSelected: boolean, isInPickingMode: boolean, gizmoMode: number }> {
  22. private _gizmoLayerOnPointerObserver: Nullable<Observer<PointerInfo>>;
  23. private _onPointerObserver: Nullable<Observer<PointerInfo>>;
  24. private _onSelectionChangeObserver: Nullable<Observer<any>>;
  25. private _selectedEntity: any;
  26. constructor(props: ISceneTreeItemComponentProps) {
  27. super(props);
  28. const scene = this.props.scene;
  29. let gizmoMode = 0;
  30. if (scene.reservedDataStore && scene.reservedDataStore.gizmoManager) {
  31. const manager: GizmoManager = scene.reservedDataStore.gizmoManager;
  32. if (manager.positionGizmoEnabled) {
  33. gizmoMode = 1;
  34. } else if (manager.rotationGizmoEnabled) {
  35. gizmoMode = 2;
  36. } else if (manager.scaleGizmoEnabled) {
  37. gizmoMode = 3;
  38. }
  39. }
  40. this.state = { isSelected: false, isInPickingMode: false, gizmoMode: gizmoMode };
  41. }
  42. shouldComponentUpdate(nextProps: ISceneTreeItemComponentProps, nextState: { isSelected: boolean, isInPickingMode: boolean }) {
  43. if (nextProps.selectedEntity) {
  44. if (nextProps.scene === nextProps.selectedEntity) {
  45. nextState.isSelected = true;
  46. return true;
  47. } else {
  48. nextState.isSelected = false;
  49. }
  50. }
  51. return true;
  52. }
  53. componentWillMount() {
  54. if (!this.props.onSelectionChangedObservable) {
  55. return;
  56. }
  57. const scene = this.props.scene;
  58. this._onSelectionChangeObserver = this.props.onSelectionChangedObservable.add((entity) => {
  59. this._selectedEntity = entity;
  60. if (scene.reservedDataStore && scene.reservedDataStore.gizmoManager) {
  61. const manager: GizmoManager = scene.reservedDataStore.gizmoManager;
  62. const className = entity.getClassName();
  63. if (className === "TransformNode" || className.indexOf("Mesh") !== -1) {
  64. manager.attachToMesh(entity);
  65. }else if(className.indexOf("Light") !== -1 && this._selectedEntity.reservedDataStore && this._selectedEntity.reservedDataStore.lightGizmo){
  66. manager.attachToMesh(this._selectedEntity.reservedDataStore.lightGizmo.attachedMesh);
  67. }
  68. }
  69. });
  70. }
  71. componentWillUnmount() {
  72. const scene = this.props.scene;
  73. if (this._onPointerObserver) {
  74. scene.onPointerObservable.remove(this._onPointerObserver);
  75. this._onPointerObserver = null;
  76. }
  77. if (this._gizmoLayerOnPointerObserver) {
  78. scene.onPointerObservable.remove(this._gizmoLayerOnPointerObserver);
  79. this._gizmoLayerOnPointerObserver = null;
  80. }
  81. if (this._onSelectionChangeObserver && this.props.onSelectionChangedObservable) {
  82. this.props.onSelectionChangedObservable.remove(this._onSelectionChangeObserver);
  83. }
  84. }
  85. onSelect() {
  86. if (!this.props.onSelectionChangedObservable) {
  87. return;
  88. }
  89. const scene = this.props.scene;
  90. this.props.onSelectionChangedObservable.notifyObservers(scene);
  91. }
  92. onPickingMode() {
  93. const scene = this.props.scene;
  94. if (this._onPointerObserver) {
  95. scene.onPointerObservable.remove(this._onPointerObserver);
  96. this._onPointerObserver = null;
  97. }
  98. if (!this.state.isInPickingMode) {
  99. this._onPointerObserver = scene.onPointerObservable.add(() => {
  100. const pickPosition = scene.unTranslatedPointer;
  101. const pickInfo = scene.pick(pickPosition.x, pickPosition.y, (mesh) => mesh.isEnabled() && mesh.isVisible && mesh.getTotalVertices() > 0);
  102. // Pick light gizmos first
  103. if(this.props.globalState.lightGizmos.length > 0){
  104. var gizmoScene = this.props.globalState.lightGizmos[0].gizmoLayer.utilityLayerScene;
  105. let pickInfo = gizmoScene.pick(pickPosition.x, pickPosition.y, (m:any)=>{
  106. for(var g of (this.props.globalState.lightGizmos as any)){
  107. if(g.attachedMesh == m){
  108. return true;
  109. }
  110. }
  111. return false;
  112. });
  113. if (pickInfo && pickInfo.hit && this.props.onSelectionChangedObservable) {
  114. this.props.onSelectionChangedObservable.notifyObservers(pickInfo.pickedMesh);
  115. return;
  116. }
  117. }
  118. if (pickInfo && pickInfo.hit && this.props.onSelectionChangedObservable) {
  119. this.props.onSelectionChangedObservable.notifyObservers(pickInfo.pickedMesh);
  120. }
  121. }, PointerEventTypes.POINTERTAP);
  122. }
  123. this.setState({ isInPickingMode: !this.state.isInPickingMode });
  124. }
  125. setGizmoMode(mode: number) {
  126. const scene = this.props.scene;
  127. if (!scene.reservedDataStore) {
  128. scene.reservedDataStore = {};
  129. }
  130. if (this._gizmoLayerOnPointerObserver) {
  131. scene.onPointerObservable.remove(this._gizmoLayerOnPointerObserver);
  132. this._gizmoLayerOnPointerObserver = null;
  133. }
  134. if (!scene.reservedDataStore.gizmoManager) {
  135. scene.reservedDataStore.gizmoManager = new GizmoManager(scene);
  136. }
  137. const manager: GizmoManager = scene.reservedDataStore.gizmoManager;
  138. // Allow picking of light gizmo when a gizmo mode is selected
  139. this._gizmoLayerOnPointerObserver = UtilityLayerRenderer.DefaultUtilityLayer.utilityLayerScene.onPointerObservable.add((pointerInfo)=>{
  140. if (pointerInfo.type == PointerEventTypes.POINTERDOWN) {
  141. if (pointerInfo.pickInfo && pointerInfo.pickInfo.pickedMesh) {
  142. var node: Nullable<any> = pointerInfo.pickInfo.pickedMesh;
  143. // Attach to the most parent node
  144. while (node && node.parent != null) {
  145. node = node.parent;
  146. }
  147. for(var gizmo of this.props.globalState.lightGizmos){
  148. if(gizmo._rootMesh == node){
  149. manager.attachToMesh(gizmo.attachedMesh);
  150. }
  151. }
  152. }
  153. }
  154. })
  155. manager.positionGizmoEnabled = false;
  156. manager.rotationGizmoEnabled = false;
  157. manager.scaleGizmoEnabled = false;
  158. if (this.state.gizmoMode === mode) {
  159. mode = 0;
  160. manager.dispose();
  161. scene.reservedDataStore.gizmoManager = null;
  162. } else {
  163. switch (mode) {
  164. case 1:
  165. manager.positionGizmoEnabled = true;
  166. break;
  167. case 2:
  168. manager.rotationGizmoEnabled = true;
  169. break;
  170. case 3:
  171. manager.scaleGizmoEnabled = true;
  172. break;
  173. }
  174. if (this._selectedEntity && this._selectedEntity.getClassName) {
  175. const className = this._selectedEntity.getClassName();
  176. if (className === "TransformNode" || className.indexOf("Mesh") !== -1) {
  177. manager.attachToMesh(this._selectedEntity);
  178. } else if(className.indexOf("Light") !== -1 && this._selectedEntity.reservedDataStore && this._selectedEntity.reservedDataStore.lightGizmo){
  179. manager.attachToMesh(this._selectedEntity.reservedDataStore.lightGizmo.attachedMesh);
  180. }
  181. }
  182. }
  183. this.setState({ gizmoMode: mode });
  184. }
  185. render() {
  186. return (
  187. <div className={this.state.isSelected ? "itemContainer selected" : "itemContainer"}>
  188. <div className="sceneNode">
  189. <div className="sceneTitle" onClick={() => this.onSelect()} >
  190. <FontAwesomeIcon icon={faImage} />&nbsp;Scene
  191. </div>
  192. <div className={this.state.gizmoMode === 1 ? "translation selected icon" : "translation icon"} onClick={() => this.setGizmoMode(1)} title="Enable/Disable position mode">
  193. <FontAwesomeIcon icon={faArrowsAlt} />
  194. </div>
  195. <div className={this.state.gizmoMode === 2 ? "rotation selected icon" : "rotation icon"} onClick={() => this.setGizmoMode(2)} title="Enable/Disable rotation mode">
  196. <FontAwesomeIcon icon={faRedoAlt} />
  197. </div>
  198. <div className={this.state.gizmoMode === 3 ? "scaling selected icon" : "scaling icon"} onClick={() => this.setGizmoMode(3)} title="Enable/Disable scaling mode">
  199. <FontAwesomeIcon icon={faCompress} />
  200. </div>
  201. <div className="separator" />
  202. <div className={this.state.isInPickingMode ? "pickingMode selected icon" : "pickingMode icon"} onClick={() => this.onPickingMode()} title="Turn picking mode on/off">
  203. <FontAwesomeIcon icon={faCrosshairs} />
  204. </div>
  205. <div className="refresh icon" onClick={() => this.props.onRefresh()} title="Refresh the explorer">
  206. <FontAwesomeIcon icon={faSyncAlt} />
  207. </div>
  208. {
  209. <ExtensionsComponent target={this.props.scene} extensibilityGroups={this.props.extensibilityGroups} />
  210. }
  211. </div>
  212. </div>
  213. );
  214. }
  215. }