SelectionToolManager.cs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. /*
  2. Copyright (c) 2021 Omar Duarte
  3. Unauthorized copying of this file, via any medium is strictly prohibited.
  4. Writen by Omar Duarte, 2021.
  5. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  6. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  7. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  8. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  9. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  10. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  11. THE SOFTWARE.
  12. */
  13. using System.Linq;
  14. using UnityEngine;
  15. namespace PluginMaster
  16. {
  17. #region DATA & SETTINGS
  18. [System.Serializable]
  19. public class SelectionToolSettings : SelectionToolBase, IToolSettings, ISerializationCallbackReceiver
  20. {
  21. [SerializeField] private bool _move = true;
  22. [SerializeField] private bool _rotate = false;
  23. [SerializeField] private bool _scale = false;
  24. [SerializeField] private Space _handleSpace = Space.Self;
  25. [SerializeField] private Space _boxSpace = Space.Self;
  26. [SerializeField] private bool _paletteFilter = false;
  27. [SerializeField] private bool _brushFilter = false;
  28. [SerializeField] private LayerMask _layerFilter = -1;
  29. [SerializeField] private System.Collections.Generic.List<string> _tagFilter = null;
  30. public Space handleSpace
  31. {
  32. get => _handleSpace;
  33. set
  34. {
  35. if (_handleSpace == value) return;
  36. _handleSpace = value;
  37. if (_handleSpace == Space.World) _scale = false;
  38. DataChanged();
  39. }
  40. }
  41. public bool move
  42. {
  43. get => _move;
  44. set
  45. {
  46. if (_move == value) return;
  47. _move = value;
  48. DataChanged();
  49. }
  50. }
  51. public bool rotate
  52. {
  53. get => _rotate;
  54. set
  55. {
  56. if (_rotate == value) return;
  57. _rotate = value;
  58. DataChanged();
  59. }
  60. }
  61. public bool scale
  62. {
  63. get => _scale;
  64. set
  65. {
  66. if (_scale == value) return;
  67. _scale = value;
  68. if (_scale) _handleSpace = Space.Self;
  69. DataChanged();
  70. }
  71. }
  72. public Space boxSpace
  73. {
  74. get => _boxSpace;
  75. set
  76. {
  77. if (_boxSpace == value) return;
  78. _boxSpace = value;
  79. DataChanged();
  80. }
  81. }
  82. public bool paletteFilter
  83. {
  84. get => _paletteFilter;
  85. set
  86. {
  87. if (_paletteFilter == value) return;
  88. _paletteFilter = value;
  89. DataChanged();
  90. }
  91. }
  92. public bool brushFilter
  93. {
  94. get => _brushFilter;
  95. set
  96. {
  97. if (_brushFilter == value) return;
  98. _brushFilter = value;
  99. DataChanged();
  100. }
  101. }
  102. public LayerMask layerFilter
  103. {
  104. get => _layerFilter;
  105. set
  106. {
  107. if (_layerFilter == value) return;
  108. _layerFilter = value;
  109. DataChanged();
  110. }
  111. }
  112. public System.Collections.Generic.List<string> tagFilter
  113. {
  114. get
  115. {
  116. if (_tagFilter == null) UpdateTagFilter();
  117. return _tagFilter;
  118. }
  119. set
  120. {
  121. if (_tagFilter == value) return;
  122. _tagFilter = value;
  123. DataChanged();
  124. }
  125. }
  126. private void UpdateTagFilter()
  127. {
  128. if (_tagFilter != null) return;
  129. _tagFilter = new System.Collections.Generic.List<string>(UnityEditorInternal.InternalEditorUtility.tags);
  130. }
  131. public void OnBeforeSerialize() => UpdateTagFilter();
  132. public void OnAfterDeserialize() => UpdateTagFilter();
  133. public override void Copy(IToolSettings other)
  134. {
  135. var otherSelectionToolSettings = other as SelectionToolSettings;
  136. if (otherSelectionToolSettings == null) return;
  137. base.Copy(other);
  138. _move = otherSelectionToolSettings._move;
  139. _rotate = otherSelectionToolSettings._rotate;
  140. _scale = otherSelectionToolSettings._scale;
  141. _handleSpace = otherSelectionToolSettings._handleSpace;
  142. _boxSpace = otherSelectionToolSettings._boxSpace;
  143. _paletteFilter = otherSelectionToolSettings._paletteFilter;
  144. _brushFilter = otherSelectionToolSettings._brushFilter;
  145. _layerFilter = otherSelectionToolSettings._layerFilter;
  146. _tagFilter = otherSelectionToolSettings._tagFilter == null ? null
  147. : new System.Collections.Generic.List<string>(otherSelectionToolSettings._tagFilter);
  148. }
  149. }
  150. [System.Serializable]
  151. public class SelectionToolManager : ToolManagerBase<SelectionToolSettings> { }
  152. #endregion
  153. #region PWBIO
  154. public static partial class PWBIO
  155. {
  156. private static int _selectedBoxPointIdx = -1;
  157. private static Quaternion _selectionRotation = Quaternion.identity;
  158. private static Vector3 _selectionScale = Vector3.one;
  159. private static Vector3 _snappedPoint;
  160. private static bool _snappedPointIsVisible = false;
  161. private static bool _snappedPointIsSelected = false;
  162. private static (Vector3 position, GameObject[] selection) _selectionMoveFrom;
  163. private static bool _selectionMoving = false;
  164. private static bool _editingSelectionHandlePosition = false;
  165. private static Vector3 _tempSelectionHandle = Vector3.zero;
  166. private static bool _selectionChanged = false;
  167. private static Bounds _selectionBounds;
  168. private static bool _setSelectionOriginPosition = false;
  169. private static void SelectionDuringSceneGUI(UnityEditor.SceneView sceneView)
  170. {
  171. if (SelectionToolManager.settings.createTempColliders)
  172. PWBCore.CreateTempCollidersWithinFrustum(sceneView.camera);
  173. if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape)
  174. {
  175. _snappedPointIsSelected = false;
  176. _selectionMoving = false;
  177. if (_selectedBoxPointIdx >= 0 && _selectedBoxPointIdx != 10) _selectedBoxPointIdx = 10;
  178. else
  179. {
  180. ResetUnityCurrentTool();
  181. ToolManager.DeselectTool();
  182. return;
  183. }
  184. }
  185. if (UnityEditor.Tools.current != UnityEditor.Tool.View && UnityEditor.Tools.current != UnityEditor.Tool.None)
  186. UnityEditor.Tools.current = UnityEditor.Tool.None;
  187. if (SelectionManager.topLevelSelection.Length == 0) return;
  188. var points = SelectionPoints(sceneView.camera);
  189. if (_setSelectionOriginPosition && SnapManager.settings.snappingEnabled && !SnapManager.settings.lockedGrid)
  190. {
  191. _setSelectionOriginPosition = false;
  192. SnapManager.settings.SetOriginHeight(points[_selectedBoxPointIdx], SnapManager.settings.gridAxis);
  193. }
  194. SelectionInput(points, sceneView.in2DMode);
  195. if (_selectionMoving)
  196. {
  197. UnityEditor.Handles.CircleHandleCap(0, _selectionMoveFrom.position, sceneView.camera.transform.rotation,
  198. UnityEditor.HandleUtility.GetHandleSize(_selectionMoveFrom.position) * 0.06f, EventType.Repaint);
  199. if (_selectedBoxPointIdx >= 0)
  200. UnityEditor.Handles.DrawLine(_selectionMoveFrom.position, points[_selectedBoxPointIdx]);
  201. }
  202. bool mouseDown = Event.current.button == 0 && Event.current.type == EventType.MouseDown;
  203. bool clickOnPoint = false;
  204. bool SelectPoint(Vector3 point, int i)
  205. {
  206. if (_editingSelectionHandlePosition) return false;
  207. if (clickOnPoint) return false;
  208. var controlId = GUIUtility.GetControlID(FocusType.Passive);
  209. var distFromMouse = UnityEditor.HandleUtility.DistanceToRectangle(point, Quaternion.identity, 0f);
  210. UnityEditor.HandleUtility.AddControl(controlId, distFromMouse);
  211. if (UnityEditor.HandleUtility.nearestControl != controlId) return false;
  212. DrawDotHandleCap(point, 1f, 1.2f);
  213. if (!mouseDown) return false;
  214. _selectedBoxPointIdx = i;
  215. clickOnPoint = true;
  216. Event.current.Use();
  217. return true;
  218. }
  219. for (int i = 0; i < points.Count; ++i)
  220. {
  221. if (SelectPoint(points[i], i)) _snappedPointIsSelected = false;
  222. if (clickOnPoint) break;
  223. }
  224. if (_snappedPointIsVisible || _snappedPointIsSelected)
  225. {
  226. points.Add(_snappedPoint);
  227. if (SelectPoint(_snappedPoint, points.Count - 1)) _snappedPointIsSelected = true;
  228. }
  229. if (_selectionChanged)
  230. {
  231. _tempSelectionHandle = Vector3.zero;
  232. _selectionChanged = false;
  233. ApplySelectionFilters();
  234. }
  235. if (_editingSelectionHandlePosition)
  236. {
  237. _selectedBoxPointIdx = 11;
  238. UnityEditor.Handles.CircleHandleCap(0, points[11], sceneView.camera.transform.rotation,
  239. UnityEditor.HandleUtility.GetHandleSize(points[11]) * 0.06f, EventType.Repaint);
  240. }
  241. if (_selectedBoxPointIdx >= 0)
  242. {
  243. var rotation = GetSelectionRotation();
  244. if (_editingSelectionHandlePosition)
  245. {
  246. var delta = points[_selectedBoxPointIdx];
  247. points[_selectedBoxPointIdx] = UnityEditor.Handles.PositionHandle(points[_selectedBoxPointIdx], rotation);
  248. delta = points[_selectedBoxPointIdx] - delta;
  249. _tempSelectionHandle += delta;
  250. }
  251. else
  252. {
  253. MoveSelection(rotation, points, sceneView);
  254. RotateSelection(rotation, points);
  255. ScaleSelection(rotation, points);
  256. }
  257. }
  258. else _editingSelectionHandlePosition = false;
  259. }
  260. private static void SelectionInput(System.Collections.Generic.List<Vector3> points, bool in2DMode)
  261. {
  262. if (UnityEditor.Tools.current == UnityEditor.Tool.Move) return;
  263. var keyCode = Event.current.keyCode;
  264. if (PWBSettings.shortcuts.selectionTogglePositionHandle.Check())
  265. {
  266. SelectionToolManager.settings.move = !SelectionToolManager.settings.move;
  267. PWBToolbar.RepaintWindow();
  268. }
  269. else if (PWBSettings.shortcuts.selectionToggleRotationHandle.Check())
  270. {
  271. SelectionToolManager.settings.rotate = !SelectionToolManager.settings.rotate;
  272. PWBToolbar.RepaintWindow();
  273. }
  274. else if (PWBSettings.shortcuts.selectionToggleScaleHandle.Check())
  275. {
  276. SelectionToolManager.settings.scale = !SelectionToolManager.settings.scale;
  277. PWBToolbar.RepaintWindow();
  278. }
  279. else if (Event.current.type == EventType.KeyDown
  280. && (PWBSettings.shortcuts.selectionEditCustomHandle.Check()
  281. || (_editingSelectionHandlePosition && (Event.current.keyCode == KeyCode.Escape
  282. || Event.current.keyCode == KeyCode.Return))))
  283. {
  284. _editingSelectionHandlePosition = !_editingSelectionHandlePosition;
  285. }
  286. else if (_snappedToVertex && _selectedBoxPointIdx < 0)
  287. {
  288. _snappedPointIsVisible = false;
  289. var mouseRay = UnityEditor.HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
  290. if (SnapToVertex(mouseRay, out RaycastHit snappedHit, in2DMode, SelectionManager.topLevelSelection))
  291. {
  292. _snappedPoint = snappedHit.point;
  293. _snappedPointIsVisible = true;
  294. }
  295. }
  296. else if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return
  297. && _selectedBoxPointIdx >= 0)
  298. {
  299. _editingSelectionHandlePosition = false;
  300. if (_selectionMoving)
  301. {
  302. var delta = points[_selectedBoxPointIdx] - _selectionMoveFrom.position;
  303. foreach (var obj in _selectionMoveFrom.selection)
  304. {
  305. if (obj == null) continue;
  306. UnityEditor.Undo.RecordObject(obj.transform, "Move Selection");
  307. obj.transform.position += delta;
  308. }
  309. _selectionMoving = false;
  310. SelectionManager.UpdateSelection();
  311. _selectedBoxPointIdx = -1;
  312. }
  313. else
  314. {
  315. _selectionMoveFrom = (points[_selectedBoxPointIdx], SelectionManager.topLevelSelection);
  316. _selectionMoving = true;
  317. }
  318. }
  319. else if (PWBSettings.shortcuts.selectionRotate90XCCW.Check())
  320. RotateSelection90Deg(Vector3.left, points);
  321. else if (PWBSettings.shortcuts.selectionRotate90XCW.Check())
  322. RotateSelection90Deg(Vector3.right, points);
  323. else if (PWBSettings.shortcuts.selectionRotate90YCCW.Check())
  324. RotateSelection90Deg(Vector3.down, points);
  325. else if (PWBSettings.shortcuts.selectionRotate90YCW.Check())
  326. RotateSelection90Deg(Vector3.up, points);
  327. else if (PWBSettings.shortcuts.selectionRotate90ZCCW.Check())
  328. RotateSelection90Deg(Vector3.back, points);
  329. else if (PWBSettings.shortcuts.selectionRotate90ZCW.Check())
  330. RotateSelection90Deg(Vector3.forward, points);
  331. else if (PWBSettings.shortcuts.selectionToggleSpace.Check())
  332. {
  333. SelectionToolManager.settings.handleSpace = SelectionToolManager.settings.handleSpace == Space.Self
  334. ? Space.World : Space.Self;
  335. if (SelectionToolManager.settings.handleSpace == Space.World) ResetSelectionRotation();
  336. UnityEditor.SceneView.RepaintAll();
  337. ToolProperties.RepainWindow();
  338. Event.current.Use();
  339. }
  340. }
  341. public static void ApplySelectionFilters()
  342. {
  343. var selection = SelectionManager.topLevelSelection;
  344. if (selection == null) SelectionManager.UpdateSelection();
  345. if (SelectionToolManager.settings.paletteFilter)
  346. {
  347. if (PaletteManager.selectedPalette == null) selection = new GameObject[0];
  348. else selection = selection.Where(obj => PaletteManager.selectedPalette.ContainsSceneObject(obj)).ToArray();
  349. }
  350. if (SelectionToolManager.settings.brushFilter)
  351. {
  352. if (PaletteManager.selectedBrush == null) selection = new GameObject[0];
  353. else selection = selection.Where(obj => PaletteManager.selectedBrush.ContainsSceneObject(obj)).ToArray();
  354. }
  355. if (SelectionToolManager.settings.layerFilter != -1)
  356. {
  357. var layerMask = SelectionToolManager.settings.layerFilter;
  358. selection = selection.Where(obj => (layerMask & (1 << obj.layer)) != 0).ToArray();
  359. }
  360. if (SelectionToolManager.settings.tagFilter.Count > 0)
  361. selection = selection.Where(obj => SelectionToolManager.settings.tagFilter.Contains(obj.tag)).ToArray();
  362. else selection = new GameObject[0];
  363. UnityEditor.Selection.objects = selection;
  364. }
  365. private static void EmbedSelectionInSurface(Quaternion rotation)
  366. {
  367. PWBCore.SetActiveTempColliders(SelectionManager.topLevelSelection, false);
  368. var placeOnSurfaceData = new PlaceOnSurfaceUtils.PlaceOnSurfaceData();
  369. placeOnSurfaceData.projectionDirectionSpace = Space.World;
  370. placeOnSurfaceData.rotateToSurface = false;
  371. var objHeight = new float[SelectionManager.topLevelSelection.Length];
  372. for (int i = 0; i < SelectionManager.topLevelSelection.Length; ++i)
  373. {
  374. var obj = SelectionManager.topLevelSelection[i];
  375. objHeight[i] = BoundsUtils.GetMagnitude(obj.transform);
  376. obj.SetActive(false);
  377. }
  378. for (int i = 0; i < SelectionManager.topLevelSelection.Length; ++i)
  379. {
  380. var obj = SelectionManager.topLevelSelection[i];
  381. var bottomVertices = BoundsUtils.GetBottomVertices(obj.transform);
  382. var bottomMagnitude = Mathf.Abs(BoundsUtils.GetBottomMagnitude(obj.transform));
  383. var TRS = obj.transform.localToWorldMatrix;
  384. var surfceDistance = SelectionToolManager.settings.embedAtPivotHeight
  385. ? GetPivotDistanceToSurfaceSigned(obj.transform.position, bottomMagnitude, true, true)
  386. : GetBottomDistanceToSurface(bottomVertices, TRS, bottomMagnitude,
  387. paintOnPalettePrefabs: true, castOnMeshesWithoutCollider: true, out Transform surfaceTransform);
  388. surfceDistance -= SelectionToolManager.settings.surfaceDistance;
  389. if (surfceDistance != 0f)
  390. {
  391. var euler = obj.transform.rotation.eulerAngles;
  392. var delta = obj.transform.rotation * new Vector3(0f, -surfceDistance, 0f);
  393. obj.transform.position += obj.transform.rotation * new Vector3(0f, -surfceDistance, 0f);
  394. }
  395. if (SelectionToolManager.settings.rotateToTheSurface)
  396. {
  397. var down = obj.transform.rotation * Vector3.down;
  398. var ray = new Ray(obj.transform.position - down * objHeight[i], down);
  399. if (MouseRaycast(ray, out RaycastHit hitInfo, out GameObject collider,
  400. float.MaxValue, -1, true, true))
  401. {
  402. var tangent = Vector3.Cross(hitInfo.normal, Vector3.left);
  403. if (tangent.sqrMagnitude < 0.000001) tangent = Vector3.Cross(hitInfo.normal, Vector3.back);
  404. tangent = tangent.normalized;
  405. obj.transform.rotation = Quaternion.LookRotation(tangent, hitInfo.normal);
  406. }
  407. }
  408. }
  409. foreach (var obj in SelectionManager.topLevelSelection) obj.SetActive(true);
  410. _selectionBounds = BoundsUtils.GetSelectionBounds(SelectionManager.topLevelSelection, rotation);
  411. PWBCore.SetActiveTempColliders(SelectionManager.topLevelSelection, true);
  412. }
  413. public static void EmbedSelectionInSurface() => EmbedSelectionInSurface(_selectionRotation);
  414. private static void RotateSelection90Deg(Vector3 axis, System.Collections.Generic.List<Vector3> points)
  415. {
  416. var rotation = _selectionRotation;
  417. foreach (var obj in SelectionManager.topLevelSelection)
  418. {
  419. if (obj == null)
  420. {
  421. SelectionManager.UpdateSelection();
  422. return;
  423. }
  424. UnityEditor.Undo.RecordObject(obj.transform, "Rotate Selection");
  425. obj.transform.RotateAround(points[_selectedBoxPointIdx < 0 ? 10 : _selectedBoxPointIdx],
  426. rotation * axis, 90);
  427. }
  428. _selectionRotation = rotation * Quaternion.AngleAxis(90, axis);
  429. var localCenter = _selectionBounds.center - points[_selectedBoxPointIdx];
  430. _selectionBounds.center = (Quaternion.AngleAxis(90, axis) * localCenter) + points[_selectedBoxPointIdx];
  431. if (SelectionToolManager.settings.embedInSurface) EmbedSelectionInSurface();
  432. PWBCore.UpdateTempCollidersTransforms(SelectionManager.topLevelSelection);
  433. }
  434. private static void MoveSelection(Quaternion rotation,
  435. System.Collections.Generic.List<Vector3> points, UnityEditor.SceneView sceneView)
  436. {
  437. if (!SelectionToolManager.settings.move) return;
  438. if (SelectionToolManager.settings.handleSpace == Space.World) rotation = Quaternion.identity;
  439. else if (SelectionManager.topLevelSelection.Length == 1)
  440. rotation = SelectionManager.topLevelSelection[0].transform.rotation;
  441. void SetSetectedPoint(Vector3 value) => points[_selectedBoxPointIdx] = value;
  442. var prevPosition = points[_selectedBoxPointIdx];
  443. SetSetectedPoint(UnityEditor.Handles.PositionHandle(points[_selectedBoxPointIdx], rotation));
  444. if (prevPosition == points[_selectedBoxPointIdx]) return;
  445. SetSetectedPoint(SnapAndUpdateGridOrigin(points[_selectedBoxPointIdx],
  446. SnapManager.settings.snappingEnabled, true, true, true, Vector3.down));
  447. if (_snappedPointIsSelected) _snappedPoint = points[_selectedBoxPointIdx];
  448. if (prevPosition == points[_selectedBoxPointIdx]) return;
  449. if (_snapToVertex)
  450. {
  451. if (SnapToVertex(UnityEditor.HandleUtility.GUIPointToWorldRay(Event.current.mousePosition),
  452. out RaycastHit closestVertexInfo, sceneView.in2DMode, null))
  453. SetSetectedPoint(closestVertexInfo.point);
  454. }
  455. else points[_selectedBoxPointIdx] = SnapAndUpdateGridOrigin(points[_selectedBoxPointIdx],
  456. SnapManager.settings.snappingEnabled, true, true,
  457. !SelectionToolManager.settings.embedInSurface, Vector3.down);
  458. if (prevPosition == points[_selectedBoxPointIdx]) return;
  459. var delta = points[_selectedBoxPointIdx] - prevPosition;
  460. foreach (var obj in SelectionManager.topLevelSelection)
  461. {
  462. if (obj == null)
  463. {
  464. SelectionManager.UpdateSelection();
  465. return;
  466. }
  467. UnityEditor.Undo.RecordObject(obj.transform, "Move Selection");
  468. obj.transform.position += delta;
  469. }
  470. _selectionBounds.center += delta;
  471. if (SelectionToolManager.settings.embedInSurface) EmbedSelectionInSurface();
  472. PWBCore.UpdateTempCollidersTransforms(SelectionManager.topLevelSelection);
  473. }
  474. private static void RotateSelection(Quaternion rotation, System.Collections.Generic.List<Vector3> points)
  475. {
  476. if (!SelectionToolManager.settings.rotate) return;
  477. if (SelectionToolManager.settings.handleSpace == Space.Self && SelectionManager.topLevelSelection.Length == 1)
  478. {
  479. rotation = SelectionManager.topLevelSelection[0].transform.rotation;
  480. }
  481. var prevRotation = rotation;
  482. var newRotation = UnityEditor.Handles.RotationHandle(prevRotation, points[_selectedBoxPointIdx]);
  483. if (prevRotation == newRotation) return;
  484. _selectionRotation = newRotation;
  485. var angle = Quaternion.Angle(prevRotation, newRotation);
  486. var axis = Vector3.Cross(prevRotation * Vector3.forward, newRotation * Vector3.forward);
  487. if (axis == Vector3.zero) axis = Vector3.Cross(prevRotation * Vector3.up, newRotation * Vector3.up);
  488. axis.Normalize();
  489. foreach (var obj in SelectionManager.topLevelSelection)
  490. {
  491. if (obj == null)
  492. {
  493. SelectionManager.UpdateSelection();
  494. return;
  495. }
  496. UnityEditor.Undo.RecordObject(obj.transform, "Rotate Selection");
  497. obj.transform.RotateAround(points[_selectedBoxPointIdx], axis, angle);
  498. }
  499. var localCenter = _selectionBounds.center - points[_selectedBoxPointIdx];
  500. _selectionBounds.center = (Quaternion.AngleAxis(angle, axis) * localCenter)
  501. + points[_selectedBoxPointIdx];
  502. if (SelectionToolManager.settings.embedInSurface) EmbedSelectionInSurface(_selectionRotation);
  503. PWBCore.UpdateTempCollidersTransforms(SelectionManager.topLevelSelection);
  504. }
  505. private static void ScaleSelection(Quaternion rotation, System.Collections.Generic.List<Vector3> points)
  506. {
  507. if (!SelectionToolManager.settings.scale) return;
  508. var prevScale = _selectionScale;
  509. var newScale = UnityEditor.Handles.ScaleHandle(prevScale, points[_selectedBoxPointIdx],
  510. rotation, UnityEditor.HandleUtility.GetHandleSize(points[_selectedBoxPointIdx]) * 1.4f);
  511. if (prevScale == newScale) return;
  512. _selectionScale = newScale;
  513. var scaleFactor = new Vector3(
  514. prevScale.x == 0 ? newScale.x : newScale.x / prevScale.x,
  515. prevScale.y == 0 ? newScale.y : newScale.y / prevScale.y,
  516. prevScale.z == 0 ? newScale.z : newScale.z / prevScale.z);
  517. var pivot = new GameObject();
  518. pivot.hideFlags = HideFlags.HideAndDontSave;
  519. pivot.transform.position = points[_selectedBoxPointIdx];
  520. pivot.transform.rotation = rotation;
  521. foreach (var obj in SelectionManager.topLevelSelection)
  522. {
  523. if (obj == null)
  524. {
  525. SelectionManager.UpdateSelection();
  526. break;
  527. }
  528. UnityEditor.Undo.RecordObject(obj.transform, "Scale Selection");
  529. pivot.transform.localScale = Vector3.one;
  530. var localPosition = pivot.transform.InverseTransformPoint(obj.transform.position);
  531. pivot.transform.localScale = scaleFactor;
  532. obj.transform.position = pivot.transform.TransformPoint(localPosition);
  533. obj.transform.localScale = Vector3.Scale(obj.transform.localScale, scaleFactor);
  534. }
  535. GameObject.DestroyImmediate(pivot);
  536. var pivotToCenter = _selectionBounds.center - points[_selectedBoxPointIdx];
  537. _selectionBounds.center = points[_selectedBoxPointIdx] + Vector3.Scale(pivotToCenter, scaleFactor);
  538. _selectionBounds.size = Vector3.Scale(_selectionBounds.size, scaleFactor);
  539. if (SelectionToolManager.settings.embedInSurface) EmbedSelectionInSurface();
  540. PWBCore.UpdateTempCollidersTransforms(SelectionManager.topLevelSelection);
  541. }
  542. public static void ResetSelectionRotation()
  543. {
  544. _selectionRotation = Quaternion.identity;
  545. UpdateSelection();
  546. }
  547. private static Quaternion GetSelectionRotation()
  548. {
  549. var rotation = _selectionRotation;
  550. if (SelectionManager.topLevelSelection.Length == 1)
  551. {
  552. if (SelectionManager.topLevelSelection[0] == null) SelectionManager.UpdateSelection();
  553. else if (SelectionToolManager.settings.boxSpace == Space.Self)
  554. rotation = SelectionManager.topLevelSelection[0].transform.rotation;
  555. }
  556. else if (SelectionToolManager.settings.handleSpace == Space.Self)
  557. {
  558. var count = 0;
  559. var avgForward = Vector3.forward;
  560. var avgUp = Vector3.up;
  561. if(SelectionManager.topLevelSelection.Length > 0)
  562. {
  563. avgForward = Vector3.zero;
  564. avgUp = Vector3.zero;
  565. }
  566. foreach (var obj in SelectionManager.topLevelSelection)
  567. {
  568. if (obj == null) continue;
  569. ++count;
  570. avgForward += obj.transform.rotation * Vector3.forward;
  571. avgUp += obj.transform.rotation * Vector3.up;
  572. }
  573. avgForward /= count;
  574. avgUp /= count;
  575. rotation = Quaternion.LookRotation(avgForward, avgUp);
  576. }
  577. return rotation;
  578. }
  579. private static System.Collections.Generic.List<Vector3> SelectionPoints(Camera camera)
  580. {
  581. var rotation = GetSelectionRotation();
  582. var bounds = _selectionBounds;
  583. var halfSizeRotated = rotation * bounds.size / 2;
  584. var min = bounds.center - halfSizeRotated;
  585. var max = bounds.center + halfSizeRotated;
  586. var points = new System.Collections.Generic.List<Vector3>
  587. {
  588. min,
  589. min + rotation * new Vector3(bounds.size.x, 0f, 0f),
  590. min + rotation * new Vector3(bounds.size.x, 0f, bounds.size.z),
  591. min + rotation * new Vector3(0f, 0f, bounds.size.z),
  592. min + rotation * new Vector3(0f, bounds.size.y, 0f),
  593. min + rotation * new Vector3(bounds.size.x, bounds.size.y, 0f),
  594. max,
  595. min + rotation * new Vector3(0f, bounds.size.y, bounds.size.z),
  596. min + rotation * new Vector3(bounds.size.x, 0f, bounds.size.z) / 2,
  597. max - rotation * new Vector3(bounds.size.x, 0f, bounds.size.z) / 2,
  598. };
  599. var visibleIdx = GetVisiblePoints(points.ToArray(), camera);
  600. points.Add(bounds.center);
  601. points.Add(bounds.center + _selectionRotation * _tempSelectionHandle);
  602. void DrawLine(Vector3[] line, float alpha = 1f)
  603. {
  604. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.5f);
  605. UnityEditor.Handles.DrawAAPolyLine(10, line);
  606. UnityEditor.Handles.color = new Color(1f, 1f, 1f, 0.3f * alpha);
  607. UnityEditor.Handles.DrawAAPolyLine(4, line);
  608. }
  609. var visibleLines = new System.Collections.Generic.List<Vector3[]>();
  610. float ocludedAlpha = 0.5f;
  611. for (int i = 0; i < 8; ++i)
  612. {
  613. var visibleLine = visibleIdx.Contains(i) && visibleIdx.Contains(i + 4);
  614. if (i < 4)
  615. {
  616. var vLine = new Vector3[] { points[i],
  617. points[i] + rotation * new Vector3(0f, bounds.size.y, 0f) };
  618. if (visibleLine) visibleLines.Add(vLine);
  619. else DrawLine(vLine, ocludedAlpha);
  620. points.Add(vLine[0] + (vLine[1] - vLine[0]) / 2);
  621. }
  622. int nextI = ((i + 1) % 4) + 4 * (i / 4);
  623. visibleLine = visibleIdx.Contains(i) && visibleIdx.Contains(nextI);
  624. var hLine = new Vector3[] { points[i], points[nextI] };
  625. if (visibleLine) visibleLines.Add(hLine);
  626. else DrawLine(hLine, ocludedAlpha);
  627. var midpoint = hLine[0] + (hLine[1] - hLine[0]) / 2;
  628. points.Add(midpoint);
  629. if (i < 4) points.Add(midpoint + rotation * new Vector3(0f, bounds.size.y / 2, 0f));
  630. }
  631. foreach (var line in visibleLines) DrawLine(line);
  632. for (int i = 0; i < 8; ++i)
  633. {
  634. var alpha = visibleIdx.Contains(i) ? 1f : 0.3f;
  635. DrawDotHandleCap(points[i], alpha);
  636. }
  637. DrawDotHandleCap(points[11], 1);
  638. if(SelectionManager.topLevelSelection.Length == 1)
  639. {
  640. var pivotPosition = SelectionManager.topLevelSelection[0].transform.position;
  641. points.Add(pivotPosition);
  642. DrawDotHandleCap(pivotPosition, isPivot: true);
  643. }
  644. return points;
  645. }
  646. public static void SetSelectionOriginPosition() => _setSelectionOriginPosition = true;
  647. #region VISIBLE POINTS
  648. private static System.Collections.Generic.HashSet<int> GetVisiblePoints(Vector3[] points, Camera camera)
  649. {
  650. var resultSet = new System.Collections.Generic.HashSet<int>(GrahamScan(points));
  651. if (resultSet.Count == 6)
  652. {
  653. var ocluded = new System.Collections.Generic.List<int>();
  654. for (int i = 0; i < points.Length; ++i)
  655. {
  656. if (resultSet.Contains(i)) continue;
  657. ocluded.Add(i);
  658. }
  659. if ((ocluded[0] / 4 == ocluded[1] / 4) || (ocluded[1] == ocluded[0] + 4))
  660. return resultSet;
  661. var nearestIdx = camera.transform.InverseTransformPoint(points[ocluded[0]]).z
  662. < camera.transform.InverseTransformPoint(points[ocluded[1]]).z ? ocluded[0] : ocluded[1];
  663. resultSet.Add(nearestIdx);
  664. }
  665. return resultSet;
  666. }
  667. private static int[] GrahamScan(Vector3[] points)
  668. {
  669. var screenPoints = new System.Collections.Generic.List<BoxPoint>();
  670. for (int i = 0; i < points.Length; ++i)
  671. screenPoints.Add(new BoxPoint(i, UnityEditor.HandleUtility.WorldToGUIPoint(points[i])));
  672. var p0 = screenPoints[0];
  673. foreach (var value in screenPoints)
  674. {
  675. if (p0.point.y > value.point.y) p0 = value;
  676. }
  677. var order = new System.Collections.Generic.List<BoxPoint>();
  678. foreach (var point in screenPoints)
  679. {
  680. if (p0 != point) order.Add(point);
  681. }
  682. order = MergeSort(p0, order);
  683. var result = new System.Collections.Generic.List<BoxPoint>();
  684. result.Add(p0);
  685. result.Add(order[0]);
  686. result.Add(order[1]);
  687. order.RemoveAt(0);
  688. order.RemoveAt(0);
  689. foreach (var value in order) KeepLeft(result, value);
  690. var resultIdx = new int[result.Count];
  691. for (int i = 0; i < result.Count; ++i) resultIdx[i] = result[i];
  692. return resultIdx;
  693. }
  694. private class BoxPoint
  695. {
  696. public int idx = -1;
  697. public Vector2 point = Vector2.zero;
  698. public BoxPoint(int idx, Vector2 point) => (this.idx, this.point) = (idx, point);
  699. public override int GetHashCode()
  700. {
  701. int hashCode = 386348313;
  702. hashCode = hashCode * -1521134295 + idx.GetHashCode();
  703. hashCode = hashCode * -1521134295 + point.GetHashCode();
  704. return hashCode;
  705. }
  706. public bool Equals(BoxPoint other) => GetHashCode() == other.GetHashCode();
  707. public override bool Equals(object obj) => Equals(obj as BoxPoint);
  708. public static bool operator ==(BoxPoint l, BoxPoint r) => l.Equals(r);
  709. public static bool operator !=(BoxPoint l, BoxPoint r) => !l.Equals(r);
  710. public static implicit operator Vector2(BoxPoint value) => value.point;
  711. public static implicit operator int(BoxPoint value) => value.idx;
  712. }
  713. private static System.Collections.Generic.List<BoxPoint> MergeSort(BoxPoint p0,
  714. System.Collections.Generic.List<BoxPoint> pointList)
  715. {
  716. if (pointList.Count == 1) return pointList;
  717. var sortedList = new System.Collections.Generic.List<BoxPoint>();
  718. int middle = pointList.Count / 2;
  719. var leftArray = pointList.GetRange(0, middle);
  720. var rightArray = pointList.GetRange(middle, pointList.Count - middle);
  721. leftArray = MergeSort(p0, leftArray);
  722. rightArray = MergeSort(p0, rightArray);
  723. int leftptr = 0;
  724. int rightptr = 0;
  725. for (int i = 0; i < leftArray.Count + rightArray.Count; i++)
  726. {
  727. if (leftptr == leftArray.Count)
  728. {
  729. sortedList.Add(rightArray[rightptr]);
  730. rightptr++;
  731. }
  732. else if (rightptr == rightArray.Count)
  733. {
  734. sortedList.Add(leftArray[leftptr]);
  735. leftptr++;
  736. }
  737. else if (GetAngle(p0, leftArray[leftptr]) < GetAngle(p0, rightArray[rightptr]))
  738. {
  739. sortedList.Add(leftArray[leftptr]);
  740. leftptr++;
  741. }
  742. else
  743. {
  744. sortedList.Add(rightArray[rightptr]);
  745. rightptr++;
  746. }
  747. }
  748. return sortedList;
  749. }
  750. private static double GetAngle(Vector2 p1, Vector2 p2)
  751. {
  752. float xDiff = p2.x - p1.x;
  753. float yDiff = p2.y - p1.y;
  754. return Mathf.Atan2(yDiff, xDiff) * 180f / Mathf.PI;
  755. }
  756. private static void KeepLeft(System.Collections.Generic.List<BoxPoint> hull, BoxPoint point)
  757. {
  758. int turn(Vector2 p, Vector2 q, Vector2 r)
  759. => ((q.x - p.x) * (r.y - p.y) - (r.x - p.x) * (q.y - p.y)).CompareTo(0);
  760. while (hull.Count > 1 && turn(hull[hull.Count - 2], hull[hull.Count - 1], point) != 1)
  761. hull.RemoveAt(hull.Count - 1);
  762. if (hull.Count == 0 || hull[hull.Count - 1] != point) hull.Add(point);
  763. }
  764. #endregion
  765. }
  766. #endregion
  767. }