SceneWindow.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using BansheeEngine;
  7. namespace BansheeEditor
  8. {
  9. internal sealed class SceneWindow : EditorWindow
  10. {
  11. private const int HeaderHeight = 20;
  12. private Camera camera;
  13. private SceneCamera cameraController;
  14. private RenderTexture2D renderTexture;
  15. private GUILayoutY mainLayout;
  16. private GUIRenderTexture renderTextureGUI;
  17. private SceneViewHandler sceneViewHandler;
  18. private GUIToggle viewButton;
  19. private GUIToggle moveButton;
  20. private GUIToggle rotateButton;
  21. private GUIToggle scaleButton;
  22. private GUIToggle localCoordButton;
  23. private GUIToggle worldCoordButton;
  24. private GUIToggle pivotButton;
  25. private GUIToggle centerButton;
  26. private GUIToggle moveSnapButton;
  27. private GUIFloatField moveSnapInput;
  28. private GUIToggle rotateSnapButton;
  29. private GUIFloatField rotateSnapInput;
  30. private int editorSettingsHash = int.MaxValue;
  31. public Camera GetCamera()
  32. {
  33. return camera;
  34. }
  35. internal SceneWindow()
  36. { }
  37. private void OnInitialize()
  38. {
  39. mainLayout = GUI.layout.AddLayoutY();
  40. GUIToggleGroup handlesTG = new GUIToggleGroup();
  41. viewButton = new GUIToggle("V", handlesTG, EditorStyles.Button);
  42. moveButton = new GUIToggle("M", handlesTG, EditorStyles.Button);
  43. rotateButton = new GUIToggle("R", handlesTG, EditorStyles.Button);
  44. scaleButton = new GUIToggle("S", handlesTG, EditorStyles.Button);
  45. GUIToggleGroup coordModeTG = new GUIToggleGroup();
  46. localCoordButton = new GUIToggle("L", coordModeTG, EditorStyles.Button);
  47. worldCoordButton = new GUIToggle("W", coordModeTG, EditorStyles.Button);
  48. GUIToggleGroup pivotModeTG = new GUIToggleGroup();
  49. pivotButton = new GUIToggle("P", pivotModeTG, EditorStyles.Button);
  50. centerButton = new GUIToggle("C", pivotModeTG, EditorStyles.Button);
  51. moveSnapButton = new GUIToggle("MS", EditorStyles.Button);
  52. moveSnapInput = new GUIFloatField();
  53. rotateSnapButton = new GUIToggle("RS", EditorStyles.Button);
  54. rotateSnapInput = new GUIFloatField();
  55. viewButton.OnClick += () => OnSceneToolButtonClicked(SceneViewTool.View);
  56. moveButton.OnClick += () => OnSceneToolButtonClicked(SceneViewTool.Move);
  57. rotateButton.OnClick += () => OnSceneToolButtonClicked(SceneViewTool.Rotate);
  58. scaleButton.OnClick += () => OnSceneToolButtonClicked(SceneViewTool.Scale);
  59. localCoordButton.OnClick += () => OnCoordinateModeButtonClicked(HandleCoordinateMode.Local);
  60. worldCoordButton.OnClick += () => OnCoordinateModeButtonClicked(HandleCoordinateMode.World);
  61. pivotButton.OnClick += () => OnPivotModeButtonClicked(HandlePivotMode.Pivot);
  62. centerButton.OnClick += () => OnPivotModeButtonClicked(HandlePivotMode.Center);
  63. moveSnapButton.OnToggled += (bool active) => OnMoveSnapToggled(active);
  64. moveSnapInput.OnChanged += (float value) => OnMoveSnapValueChanged(value);
  65. rotateSnapButton.OnToggled += (bool active) => OnRotateSnapToggled(active);
  66. rotateSnapInput.OnChanged += (float value) => OnRotateSnapValueChanged(value);
  67. GUILayout handlesLayout = mainLayout.AddLayoutX();
  68. handlesLayout.AddElement(viewButton);
  69. handlesLayout.AddElement(moveButton);
  70. handlesLayout.AddElement(rotateButton);
  71. handlesLayout.AddElement(scaleButton);
  72. handlesLayout.AddSpace(10);
  73. handlesLayout.AddElement(localCoordButton);
  74. handlesLayout.AddElement(worldCoordButton);
  75. handlesLayout.AddSpace(10);
  76. handlesLayout.AddElement(pivotButton);
  77. handlesLayout.AddElement(centerButton);
  78. handlesLayout.AddFlexibleSpace();
  79. handlesLayout.AddElement(moveSnapButton);
  80. handlesLayout.AddElement(moveSnapInput);
  81. handlesLayout.AddSpace(10);
  82. handlesLayout.AddElement(rotateSnapButton);
  83. handlesLayout.AddElement(rotateSnapInput);
  84. UpdateRenderTexture(Width, Height - HeaderHeight);
  85. }
  86. private void OnDestroy()
  87. {
  88. if (camera != null)
  89. {
  90. camera.sceneObject.Destroy();
  91. }
  92. }
  93. private bool ScreenToScenePos(Vector2I screenPos, out Vector2I scenePos)
  94. {
  95. scenePos = screenPos;
  96. Vector2I windowPos = ScreenToWindowPos(screenPos);
  97. Rect2I bounds = GUILayoutUtility.CalculateBounds(renderTextureGUI);
  98. if (bounds.Contains(windowPos))
  99. {
  100. scenePos.x = windowPos.x - bounds.x;
  101. scenePos.y = windowPos.y - bounds.y;
  102. return true;
  103. }
  104. return false;
  105. }
  106. private void EditorUpdate()
  107. {
  108. // Refresh GUI buttons if needed (in case someones changes the values from script)
  109. if (editorSettingsHash != EditorSettings.Hash)
  110. {
  111. UpdateButtonStates();
  112. editorSettingsHash = EditorSettings.Hash;
  113. }
  114. // Update scene view handles and selection
  115. sceneViewHandler.Update();
  116. bool handleActive = false;
  117. if (Input.IsButtonUp(ButtonCode.MouseLeft))
  118. {
  119. if (sceneViewHandler.IsHandleActive())
  120. {
  121. sceneViewHandler.ClearHandleSelection();
  122. handleActive = true;
  123. }
  124. }
  125. if (!HasFocus)
  126. return;
  127. Vector2I scenePos;
  128. if (ScreenToScenePos(Input.PointerPosition, out scenePos))
  129. {
  130. if (Input.IsButtonDown(ButtonCode.MouseLeft))
  131. {
  132. sceneViewHandler.TrySelectHandle(scenePos);
  133. }
  134. else if (Input.IsButtonUp(ButtonCode.MouseLeft))
  135. {
  136. if (!handleActive)
  137. {
  138. bool ctrlHeld = Input.IsButtonHeld(ButtonCode.LeftControl) ||
  139. Input.IsButtonHeld(ButtonCode.RightControl);
  140. sceneViewHandler.PickObject(scenePos, ctrlHeld);
  141. }
  142. }
  143. }
  144. sceneViewHandler.UpdateHandle(scenePos, Input.PointerDelta);
  145. }
  146. protected override void WindowResized(int width, int height)
  147. {
  148. UpdateRenderTexture(width, height - HeaderHeight);
  149. base.WindowResized(width, height);
  150. }
  151. protected override void FocusChanged(bool inFocus)
  152. {
  153. if (!inFocus)
  154. {
  155. sceneViewHandler.ClearHandleSelection();
  156. }
  157. }
  158. private void OnSceneToolButtonClicked(SceneViewTool tool)
  159. {
  160. EditorApplication.ActiveSceneTool = tool;
  161. editorSettingsHash = EditorSettings.Hash;
  162. }
  163. private void OnCoordinateModeButtonClicked(HandleCoordinateMode mode)
  164. {
  165. EditorApplication.ActiveCoordinateMode = mode;
  166. editorSettingsHash = EditorSettings.Hash;
  167. }
  168. private void OnPivotModeButtonClicked(HandlePivotMode mode)
  169. {
  170. EditorApplication.ActivePivotMode = mode;
  171. editorSettingsHash = EditorSettings.Hash;
  172. }
  173. private void OnMoveSnapToggled(bool active)
  174. {
  175. Handles.MoveHandleSnapActive = active;
  176. editorSettingsHash = EditorSettings.Hash;
  177. }
  178. private void OnMoveSnapValueChanged(float value)
  179. {
  180. Handles.MoveSnapAmount = MathEx.Clamp(value, 0.01f, 1000.0f);
  181. editorSettingsHash = EditorSettings.Hash;
  182. }
  183. private void OnRotateSnapToggled(bool active)
  184. {
  185. Handles.RotateHandleSnapActive = active;
  186. editorSettingsHash = EditorSettings.Hash;
  187. }
  188. private void OnRotateSnapValueChanged(float value)
  189. {
  190. Handles.RotateSnapAmount = MathEx.Clamp(value, 0.01f, 360.0f);
  191. editorSettingsHash = EditorSettings.Hash;
  192. }
  193. private void UpdateButtonStates()
  194. {
  195. switch (EditorApplication.ActiveSceneTool)
  196. {
  197. case SceneViewTool.View:
  198. viewButton.ToggleOn();
  199. break;
  200. case SceneViewTool.Move:
  201. moveButton.ToggleOn();
  202. break;
  203. case SceneViewTool.Rotate:
  204. rotateButton.ToggleOn();
  205. break;
  206. case SceneViewTool.Scale:
  207. scaleButton.ToggleOn();
  208. break;
  209. }
  210. switch (EditorApplication.ActiveCoordinateMode)
  211. {
  212. case HandleCoordinateMode.Local:
  213. localCoordButton.ToggleOn();
  214. break;
  215. case HandleCoordinateMode.World:
  216. worldCoordButton.ToggleOn();
  217. break;
  218. }
  219. switch (EditorApplication.ActivePivotMode)
  220. {
  221. case HandlePivotMode.Center:
  222. centerButton.ToggleOn();
  223. break;
  224. case HandlePivotMode.Pivot:
  225. pivotButton.ToggleOn();
  226. break;
  227. }
  228. if (Handles.MoveHandleSnapActive)
  229. moveSnapButton.ToggleOn();
  230. else
  231. moveSnapButton.ToggleOff();
  232. moveSnapInput.Value = Handles.MoveSnapAmount;
  233. if (Handles.RotateHandleSnapActive)
  234. rotateSnapButton.ToggleOn();
  235. else
  236. rotateSnapButton.ToggleOff();
  237. moveSnapInput.Value = Handles.RotateSnapAmount.Degrees;
  238. }
  239. private void UpdateRenderTexture(int width, int height)
  240. {
  241. width = MathEx.Max(20, width);
  242. height = MathEx.Max(20, height);
  243. renderTexture = new RenderTexture2D(PixelFormat.R8G8B8A8, width, height);
  244. renderTexture.Priority = 1;
  245. if (camera == null)
  246. {
  247. SceneObject sceneCameraSO = new SceneObject("SceneCamera");
  248. camera = sceneCameraSO.AddComponent<Camera>();
  249. camera.Target = renderTexture;
  250. camera.ViewportRect = new Rect2(0.0f, 0.0f, 1.0f, 1.0f);
  251. sceneCameraSO.Position = new Vector3(0, 0.5f, 1);
  252. sceneCameraSO.LookAt(new Vector3(0, 0, 0));
  253. camera.Priority = 1;
  254. camera.NearClipPlane = 0.005f;
  255. camera.FarClipPlane = 1000.0f;
  256. cameraController = sceneCameraSO.AddComponent<SceneCamera>();
  257. renderTextureGUI = new GUIRenderTexture(renderTexture);
  258. mainLayout.AddElement(renderTextureGUI);
  259. sceneViewHandler = new SceneViewHandler(this, camera);
  260. }
  261. else
  262. {
  263. camera.Target = renderTexture;
  264. renderTextureGUI.RenderTexture = renderTexture;
  265. }
  266. // TODO - Consider only doing the resize once user stops resizing the widget in order to reduce constant
  267. // render target destroy/create cycle for every single pixel.
  268. camera.AspectRatio = width / (float)height;
  269. }
  270. }
  271. }