123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809 |
- /*
- Copyright (c) 2021 Omar Duarte
- Unauthorized copying of this file, via any medium is strictly prohibited.
- Writen by Omar Duarte, 2021.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- */
- using System.Linq;
- using UnityEngine;
- namespace PluginMaster
- {
- #region DATA & SETTINGS
- [System.Serializable]
- public class SelectionToolSettings : SelectionToolBase, IToolSettings, ISerializationCallbackReceiver
- {
- [SerializeField] private bool _move = true;
- [SerializeField] private bool _rotate = false;
- [SerializeField] private bool _scale = false;
- [SerializeField] private Space _handleSpace = Space.Self;
- [SerializeField] private Space _boxSpace = Space.Self;
- [SerializeField] private bool _paletteFilter = false;
- [SerializeField] private bool _brushFilter = false;
- [SerializeField] private LayerMask _layerFilter = -1;
- [SerializeField] private System.Collections.Generic.List<string> _tagFilter = null;
- public Space handleSpace
- {
- get => _handleSpace;
- set
- {
- if (_handleSpace == value) return;
- _handleSpace = value;
- if (_handleSpace == Space.World) _scale = false;
- DataChanged();
- }
- }
- public bool move
- {
- get => _move;
- set
- {
- if (_move == value) return;
- _move = value;
- DataChanged();
- }
- }
- public bool rotate
- {
- get => _rotate;
- set
- {
- if (_rotate == value) return;
- _rotate = value;
- DataChanged();
- }
- }
- public bool scale
- {
- get => _scale;
- set
- {
- if (_scale == value) return;
- _scale = value;
- if (_scale) _handleSpace = Space.Self;
- DataChanged();
- }
- }
- public Space boxSpace
- {
- get => _boxSpace;
- set
- {
- if (_boxSpace == value) return;
- _boxSpace = value;
- DataChanged();
- }
- }
- public bool paletteFilter
- {
- get => _paletteFilter;
- set
- {
- if (_paletteFilter == value) return;
- _paletteFilter = value;
- DataChanged();
- }
- }
- public bool brushFilter
- {
- get => _brushFilter;
- set
- {
- if (_brushFilter == value) return;
- _brushFilter = value;
- DataChanged();
- }
- }
- public LayerMask layerFilter
- {
- get => _layerFilter;
- set
- {
- if (_layerFilter == value) return;
- _layerFilter = value;
- DataChanged();
- }
- }
- public System.Collections.Generic.List<string> tagFilter
- {
- get
- {
- if (_tagFilter == null) UpdateTagFilter();
- return _tagFilter;
- }
- set
- {
- if (_tagFilter == value) return;
- _tagFilter = value;
- DataChanged();
- }
- }
- private void UpdateTagFilter()
- {
- if (_tagFilter != null) return;
- _tagFilter = new System.Collections.Generic.List<string>(UnityEditorInternal.InternalEditorUtility.tags);
- }
- public void OnBeforeSerialize() => UpdateTagFilter();
- public void OnAfterDeserialize() => UpdateTagFilter();
- public override void Copy(IToolSettings other)
- {
- var otherSelectionToolSettings = other as SelectionToolSettings;
- if (otherSelectionToolSettings == null) return;
- base.Copy(other);
- _move = otherSelectionToolSettings._move;
- _rotate = otherSelectionToolSettings._rotate;
- _scale = otherSelectionToolSettings._scale;
- _handleSpace = otherSelectionToolSettings._handleSpace;
- _boxSpace = otherSelectionToolSettings._boxSpace;
- _paletteFilter = otherSelectionToolSettings._paletteFilter;
- _brushFilter = otherSelectionToolSettings._brushFilter;
- _layerFilter = otherSelectionToolSettings._layerFilter;
- _tagFilter = otherSelectionToolSettings._tagFilter == null ? null
- : new System.Collections.Generic.List<string>(otherSelectionToolSettings._tagFilter);
- }
- }
- [System.Serializable]
- public class SelectionToolManager : ToolManagerBase<SelectionToolSettings> { }
- #endregion
- #region PWBIO
- public static partial class PWBIO
- {
- private static int _selectedBoxPointIdx = -1;
- private static Quaternion _selectionRotation = Quaternion.identity;
- private static Vector3 _selectionScale = Vector3.one;
- private static Vector3 _snappedPoint;
- private static bool _snappedPointIsVisible = false;
- private static bool _snappedPointIsSelected = false;
- private static (Vector3 position, GameObject[] selection) _selectionMoveFrom;
- private static bool _selectionMoving = false;
- private static bool _editingSelectionHandlePosition = false;
- private static Vector3 _tempSelectionHandle = Vector3.zero;
- private static bool _selectionChanged = false;
- private static Bounds _selectionBounds;
- private static bool _setSelectionOriginPosition = false;
- private static void SelectionDuringSceneGUI(UnityEditor.SceneView sceneView)
- {
- if (SelectionToolManager.settings.createTempColliders)
- PWBCore.CreateTempCollidersWithinFrustum(sceneView.camera);
- if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape)
- {
- _snappedPointIsSelected = false;
- _selectionMoving = false;
- if (_selectedBoxPointIdx >= 0 && _selectedBoxPointIdx != 10) _selectedBoxPointIdx = 10;
- else
- {
- ResetUnityCurrentTool();
- ToolManager.DeselectTool();
- return;
- }
- }
- if (UnityEditor.Tools.current != UnityEditor.Tool.View && UnityEditor.Tools.current != UnityEditor.Tool.None)
- UnityEditor.Tools.current = UnityEditor.Tool.None;
- if (SelectionManager.topLevelSelection.Length == 0) return;
- var points = SelectionPoints(sceneView.camera);
- if (_setSelectionOriginPosition && SnapManager.settings.snappingEnabled && !SnapManager.settings.lockedGrid)
- {
- _setSelectionOriginPosition = false;
- SnapManager.settings.SetOriginHeight(points[_selectedBoxPointIdx], SnapManager.settings.gridAxis);
- }
- SelectionInput(points, sceneView.in2DMode);
- if (_selectionMoving)
- {
- UnityEditor.Handles.CircleHandleCap(0, _selectionMoveFrom.position, sceneView.camera.transform.rotation,
- UnityEditor.HandleUtility.GetHandleSize(_selectionMoveFrom.position) * 0.06f, EventType.Repaint);
- if (_selectedBoxPointIdx >= 0)
- UnityEditor.Handles.DrawLine(_selectionMoveFrom.position, points[_selectedBoxPointIdx]);
- }
- bool mouseDown = Event.current.button == 0 && Event.current.type == EventType.MouseDown;
- bool clickOnPoint = false;
- bool SelectPoint(Vector3 point, int i)
- {
- if (_editingSelectionHandlePosition) return false;
- if (clickOnPoint) return false;
- var controlId = GUIUtility.GetControlID(FocusType.Passive);
- var distFromMouse = UnityEditor.HandleUtility.DistanceToRectangle(point, Quaternion.identity, 0f);
- UnityEditor.HandleUtility.AddControl(controlId, distFromMouse);
- if (UnityEditor.HandleUtility.nearestControl != controlId) return false;
- DrawDotHandleCap(point, 1f, 1.2f);
- if (!mouseDown) return false;
- _selectedBoxPointIdx = i;
- clickOnPoint = true;
- Event.current.Use();
- return true;
- }
- for (int i = 0; i < points.Count; ++i)
- {
- if (SelectPoint(points[i], i)) _snappedPointIsSelected = false;
- if (clickOnPoint) break;
- }
- if (_snappedPointIsVisible || _snappedPointIsSelected)
- {
- points.Add(_snappedPoint);
- if (SelectPoint(_snappedPoint, points.Count - 1)) _snappedPointIsSelected = true;
- }
- if (_selectionChanged)
- {
- _tempSelectionHandle = Vector3.zero;
- _selectionChanged = false;
- ApplySelectionFilters();
- }
- if (_editingSelectionHandlePosition)
- {
- _selectedBoxPointIdx = 11;
- UnityEditor.Handles.CircleHandleCap(0, points[11], sceneView.camera.transform.rotation,
- UnityEditor.HandleUtility.GetHandleSize(points[11]) * 0.06f, EventType.Repaint);
- }
- if (_selectedBoxPointIdx >= 0)
- {
- var rotation = GetSelectionRotation();
- if (_editingSelectionHandlePosition)
- {
- var delta = points[_selectedBoxPointIdx];
- points[_selectedBoxPointIdx] = UnityEditor.Handles.PositionHandle(points[_selectedBoxPointIdx], rotation);
- delta = points[_selectedBoxPointIdx] - delta;
- _tempSelectionHandle += delta;
- }
- else
- {
- MoveSelection(rotation, points, sceneView);
- RotateSelection(rotation, points);
- ScaleSelection(rotation, points);
- }
- }
- else _editingSelectionHandlePosition = false;
- }
- private static void SelectionInput(System.Collections.Generic.List<Vector3> points, bool in2DMode)
- {
- if (UnityEditor.Tools.current == UnityEditor.Tool.Move) return;
- var keyCode = Event.current.keyCode;
- if (PWBSettings.shortcuts.selectionTogglePositionHandle.Check())
- {
- SelectionToolManager.settings.move = !SelectionToolManager.settings.move;
- PWBToolbar.RepaintWindow();
- }
- else if (PWBSettings.shortcuts.selectionToggleRotationHandle.Check())
- {
- SelectionToolManager.settings.rotate = !SelectionToolManager.settings.rotate;
- PWBToolbar.RepaintWindow();
- }
- else if (PWBSettings.shortcuts.selectionToggleScaleHandle.Check())
- {
- SelectionToolManager.settings.scale = !SelectionToolManager.settings.scale;
- PWBToolbar.RepaintWindow();
- }
- else if (Event.current.type == EventType.KeyDown
- && (PWBSettings.shortcuts.selectionEditCustomHandle.Check()
- || (_editingSelectionHandlePosition && (Event.current.keyCode == KeyCode.Escape
- || Event.current.keyCode == KeyCode.Return))))
- {
- _editingSelectionHandlePosition = !_editingSelectionHandlePosition;
- }
- else if (_snappedToVertex && _selectedBoxPointIdx < 0)
- {
- _snappedPointIsVisible = false;
- var mouseRay = UnityEditor.HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
- if (SnapToVertex(mouseRay, out RaycastHit snappedHit, in2DMode, SelectionManager.topLevelSelection))
- {
- _snappedPoint = snappedHit.point;
- _snappedPointIsVisible = true;
- }
- }
- else if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return
- && _selectedBoxPointIdx >= 0)
- {
- _editingSelectionHandlePosition = false;
- if (_selectionMoving)
- {
- var delta = points[_selectedBoxPointIdx] - _selectionMoveFrom.position;
- foreach (var obj in _selectionMoveFrom.selection)
- {
- if (obj == null) continue;
- UnityEditor.Undo.RecordObject(obj.transform, "Move Selection");
- obj.transform.position += delta;
- }
- _selectionMoving = false;
- SelectionManager.UpdateSelection();
- _selectedBoxPointIdx = -1;
- }
- else
- {
- _selectionMoveFrom = (points[_selectedBoxPointIdx], SelectionManager.topLevelSelection);
- _selectionMoving = true;
- }
- }
- else if (PWBSettings.shortcuts.selectionRotate90XCCW.Check())
- RotateSelection90Deg(Vector3.left, points);
- else if (PWBSettings.shortcuts.selectionRotate90XCW.Check())
- RotateSelection90Deg(Vector3.right, points);
- else if (PWBSettings.shortcuts.selectionRotate90YCCW.Check())
- RotateSelection90Deg(Vector3.down, points);
- else if (PWBSettings.shortcuts.selectionRotate90YCW.Check())
- RotateSelection90Deg(Vector3.up, points);
- else if (PWBSettings.shortcuts.selectionRotate90ZCCW.Check())
- RotateSelection90Deg(Vector3.back, points);
- else if (PWBSettings.shortcuts.selectionRotate90ZCW.Check())
- RotateSelection90Deg(Vector3.forward, points);
- else if (PWBSettings.shortcuts.selectionToggleSpace.Check())
- {
- SelectionToolManager.settings.handleSpace = SelectionToolManager.settings.handleSpace == Space.Self
- ? Space.World : Space.Self;
- if (SelectionToolManager.settings.handleSpace == Space.World) ResetSelectionRotation();
- UnityEditor.SceneView.RepaintAll();
- ToolProperties.RepainWindow();
- Event.current.Use();
- }
- }
- public static void ApplySelectionFilters()
- {
- var selection = SelectionManager.topLevelSelection;
- if (selection == null) SelectionManager.UpdateSelection();
- if (SelectionToolManager.settings.paletteFilter)
- {
- if (PaletteManager.selectedPalette == null) selection = new GameObject[0];
- else selection = selection.Where(obj => PaletteManager.selectedPalette.ContainsSceneObject(obj)).ToArray();
- }
- if (SelectionToolManager.settings.brushFilter)
- {
- if (PaletteManager.selectedBrush == null) selection = new GameObject[0];
- else selection = selection.Where(obj => PaletteManager.selectedBrush.ContainsSceneObject(obj)).ToArray();
- }
- if (SelectionToolManager.settings.layerFilter != -1)
- {
- var layerMask = SelectionToolManager.settings.layerFilter;
- selection = selection.Where(obj => (layerMask & (1 << obj.layer)) != 0).ToArray();
- }
- if (SelectionToolManager.settings.tagFilter.Count > 0)
- selection = selection.Where(obj => SelectionToolManager.settings.tagFilter.Contains(obj.tag)).ToArray();
- else selection = new GameObject[0];
- UnityEditor.Selection.objects = selection;
- }
- private static void EmbedSelectionInSurface(Quaternion rotation)
- {
- PWBCore.SetActiveTempColliders(SelectionManager.topLevelSelection, false);
- var placeOnSurfaceData = new PlaceOnSurfaceUtils.PlaceOnSurfaceData();
- placeOnSurfaceData.projectionDirectionSpace = Space.World;
- placeOnSurfaceData.rotateToSurface = false;
- var objHeight = new float[SelectionManager.topLevelSelection.Length];
- for (int i = 0; i < SelectionManager.topLevelSelection.Length; ++i)
- {
- var obj = SelectionManager.topLevelSelection[i];
- objHeight[i] = BoundsUtils.GetMagnitude(obj.transform);
- obj.SetActive(false);
- }
- for (int i = 0; i < SelectionManager.topLevelSelection.Length; ++i)
- {
- var obj = SelectionManager.topLevelSelection[i];
- var bottomVertices = BoundsUtils.GetBottomVertices(obj.transform);
- var bottomMagnitude = Mathf.Abs(BoundsUtils.GetBottomMagnitude(obj.transform));
- var TRS = obj.transform.localToWorldMatrix;
- var surfceDistance = SelectionToolManager.settings.embedAtPivotHeight
- ? GetPivotDistanceToSurfaceSigned(obj.transform.position, bottomMagnitude, true, true)
- : GetBottomDistanceToSurface(bottomVertices, TRS, bottomMagnitude,
- paintOnPalettePrefabs: true, castOnMeshesWithoutCollider: true, out Transform surfaceTransform);
- surfceDistance -= SelectionToolManager.settings.surfaceDistance;
- if (surfceDistance != 0f)
- {
- var euler = obj.transform.rotation.eulerAngles;
- var delta = obj.transform.rotation * new Vector3(0f, -surfceDistance, 0f);
- obj.transform.position += obj.transform.rotation * new Vector3(0f, -surfceDistance, 0f);
- }
- if (SelectionToolManager.settings.rotateToTheSurface)
- {
- var down = obj.transform.rotation * Vector3.down;
- var ray = new Ray(obj.transform.position - down * objHeight[i], down);
- if (MouseRaycast(ray, out RaycastHit hitInfo, out GameObject collider,
- float.MaxValue, -1, true, true))
- {
- var tangent = Vector3.Cross(hitInfo.normal, Vector3.left);
- if (tangent.sqrMagnitude < 0.000001) tangent = Vector3.Cross(hitInfo.normal, Vector3.back);
- tangent = tangent.normalized;
- obj.transform.rotation = Quaternion.LookRotation(tangent, hitInfo.normal);
- }
- }
- }
- foreach (var obj in SelectionManager.topLevelSelection) obj.SetActive(true);
- _selectionBounds = BoundsUtils.GetSelectionBounds(SelectionManager.topLevelSelection, rotation);
- PWBCore.SetActiveTempColliders(SelectionManager.topLevelSelection, true);
- }
- public static void EmbedSelectionInSurface() => EmbedSelectionInSurface(_selectionRotation);
- private static void RotateSelection90Deg(Vector3 axis, System.Collections.Generic.List<Vector3> points)
- {
- var rotation = _selectionRotation;
- foreach (var obj in SelectionManager.topLevelSelection)
- {
- if (obj == null)
- {
- SelectionManager.UpdateSelection();
- return;
- }
- UnityEditor.Undo.RecordObject(obj.transform, "Rotate Selection");
- obj.transform.RotateAround(points[_selectedBoxPointIdx < 0 ? 10 : _selectedBoxPointIdx],
- rotation * axis, 90);
- }
- _selectionRotation = rotation * Quaternion.AngleAxis(90, axis);
- var localCenter = _selectionBounds.center - points[_selectedBoxPointIdx];
- _selectionBounds.center = (Quaternion.AngleAxis(90, axis) * localCenter) + points[_selectedBoxPointIdx];
- if (SelectionToolManager.settings.embedInSurface) EmbedSelectionInSurface();
- PWBCore.UpdateTempCollidersTransforms(SelectionManager.topLevelSelection);
- }
- private static void MoveSelection(Quaternion rotation,
- System.Collections.Generic.List<Vector3> points, UnityEditor.SceneView sceneView)
- {
- if (!SelectionToolManager.settings.move) return;
- if (SelectionToolManager.settings.handleSpace == Space.World) rotation = Quaternion.identity;
- else if (SelectionManager.topLevelSelection.Length == 1)
- rotation = SelectionManager.topLevelSelection[0].transform.rotation;
- void SetSetectedPoint(Vector3 value) => points[_selectedBoxPointIdx] = value;
- var prevPosition = points[_selectedBoxPointIdx];
- SetSetectedPoint(UnityEditor.Handles.PositionHandle(points[_selectedBoxPointIdx], rotation));
- if (prevPosition == points[_selectedBoxPointIdx]) return;
- SetSetectedPoint(SnapAndUpdateGridOrigin(points[_selectedBoxPointIdx],
- SnapManager.settings.snappingEnabled, true, true, true, Vector3.down));
- if (_snappedPointIsSelected) _snappedPoint = points[_selectedBoxPointIdx];
- if (prevPosition == points[_selectedBoxPointIdx]) return;
- if (_snapToVertex)
- {
- if (SnapToVertex(UnityEditor.HandleUtility.GUIPointToWorldRay(Event.current.mousePosition),
- out RaycastHit closestVertexInfo, sceneView.in2DMode, null))
- SetSetectedPoint(closestVertexInfo.point);
- }
- else points[_selectedBoxPointIdx] = SnapAndUpdateGridOrigin(points[_selectedBoxPointIdx],
- SnapManager.settings.snappingEnabled, true, true,
- !SelectionToolManager.settings.embedInSurface, Vector3.down);
- if (prevPosition == points[_selectedBoxPointIdx]) return;
- var delta = points[_selectedBoxPointIdx] - prevPosition;
- foreach (var obj in SelectionManager.topLevelSelection)
- {
- if (obj == null)
- {
- SelectionManager.UpdateSelection();
- return;
- }
- UnityEditor.Undo.RecordObject(obj.transform, "Move Selection");
- obj.transform.position += delta;
- }
- _selectionBounds.center += delta;
- if (SelectionToolManager.settings.embedInSurface) EmbedSelectionInSurface();
- PWBCore.UpdateTempCollidersTransforms(SelectionManager.topLevelSelection);
- }
- private static void RotateSelection(Quaternion rotation, System.Collections.Generic.List<Vector3> points)
- {
- if (!SelectionToolManager.settings.rotate) return;
- if (SelectionToolManager.settings.handleSpace == Space.Self && SelectionManager.topLevelSelection.Length == 1)
- {
- rotation = SelectionManager.topLevelSelection[0].transform.rotation;
- }
- var prevRotation = rotation;
- var newRotation = UnityEditor.Handles.RotationHandle(prevRotation, points[_selectedBoxPointIdx]);
- if (prevRotation == newRotation) return;
- _selectionRotation = newRotation;
- var angle = Quaternion.Angle(prevRotation, newRotation);
- var axis = Vector3.Cross(prevRotation * Vector3.forward, newRotation * Vector3.forward);
- if (axis == Vector3.zero) axis = Vector3.Cross(prevRotation * Vector3.up, newRotation * Vector3.up);
- axis.Normalize();
- foreach (var obj in SelectionManager.topLevelSelection)
- {
- if (obj == null)
- {
- SelectionManager.UpdateSelection();
- return;
- }
- UnityEditor.Undo.RecordObject(obj.transform, "Rotate Selection");
- obj.transform.RotateAround(points[_selectedBoxPointIdx], axis, angle);
- }
- var localCenter = _selectionBounds.center - points[_selectedBoxPointIdx];
- _selectionBounds.center = (Quaternion.AngleAxis(angle, axis) * localCenter)
- + points[_selectedBoxPointIdx];
- if (SelectionToolManager.settings.embedInSurface) EmbedSelectionInSurface(_selectionRotation);
- PWBCore.UpdateTempCollidersTransforms(SelectionManager.topLevelSelection);
- }
- private static void ScaleSelection(Quaternion rotation, System.Collections.Generic.List<Vector3> points)
- {
- if (!SelectionToolManager.settings.scale) return;
- var prevScale = _selectionScale;
- var newScale = UnityEditor.Handles.ScaleHandle(prevScale, points[_selectedBoxPointIdx],
- rotation, UnityEditor.HandleUtility.GetHandleSize(points[_selectedBoxPointIdx]) * 1.4f);
- if (prevScale == newScale) return;
- _selectionScale = newScale;
- var scaleFactor = new Vector3(
- prevScale.x == 0 ? newScale.x : newScale.x / prevScale.x,
- prevScale.y == 0 ? newScale.y : newScale.y / prevScale.y,
- prevScale.z == 0 ? newScale.z : newScale.z / prevScale.z);
- var pivot = new GameObject();
- pivot.hideFlags = HideFlags.HideAndDontSave;
- pivot.transform.position = points[_selectedBoxPointIdx];
- pivot.transform.rotation = rotation;
- foreach (var obj in SelectionManager.topLevelSelection)
- {
- if (obj == null)
- {
- SelectionManager.UpdateSelection();
- break;
- }
- UnityEditor.Undo.RecordObject(obj.transform, "Scale Selection");
- pivot.transform.localScale = Vector3.one;
- var localPosition = pivot.transform.InverseTransformPoint(obj.transform.position);
- pivot.transform.localScale = scaleFactor;
- obj.transform.position = pivot.transform.TransformPoint(localPosition);
- obj.transform.localScale = Vector3.Scale(obj.transform.localScale, scaleFactor);
- }
- GameObject.DestroyImmediate(pivot);
- var pivotToCenter = _selectionBounds.center - points[_selectedBoxPointIdx];
- _selectionBounds.center = points[_selectedBoxPointIdx] + Vector3.Scale(pivotToCenter, scaleFactor);
- _selectionBounds.size = Vector3.Scale(_selectionBounds.size, scaleFactor);
- if (SelectionToolManager.settings.embedInSurface) EmbedSelectionInSurface();
- PWBCore.UpdateTempCollidersTransforms(SelectionManager.topLevelSelection);
- }
- public static void ResetSelectionRotation()
- {
- _selectionRotation = Quaternion.identity;
- UpdateSelection();
- }
- private static Quaternion GetSelectionRotation()
- {
- var rotation = _selectionRotation;
- if (SelectionManager.topLevelSelection.Length == 1)
- {
- if (SelectionManager.topLevelSelection[0] == null) SelectionManager.UpdateSelection();
- else if (SelectionToolManager.settings.boxSpace == Space.Self)
- rotation = SelectionManager.topLevelSelection[0].transform.rotation;
- }
- else if (SelectionToolManager.settings.handleSpace == Space.Self)
- {
- var count = 0;
- var avgForward = Vector3.forward;
- var avgUp = Vector3.up;
- if(SelectionManager.topLevelSelection.Length > 0)
- {
- avgForward = Vector3.zero;
- avgUp = Vector3.zero;
- }
- foreach (var obj in SelectionManager.topLevelSelection)
- {
- if (obj == null) continue;
- ++count;
- avgForward += obj.transform.rotation * Vector3.forward;
- avgUp += obj.transform.rotation * Vector3.up;
- }
- avgForward /= count;
- avgUp /= count;
- rotation = Quaternion.LookRotation(avgForward, avgUp);
- }
- return rotation;
- }
- private static System.Collections.Generic.List<Vector3> SelectionPoints(Camera camera)
- {
- var rotation = GetSelectionRotation();
- var bounds = _selectionBounds;
- var halfSizeRotated = rotation * bounds.size / 2;
- var min = bounds.center - halfSizeRotated;
- var max = bounds.center + halfSizeRotated;
- var points = new System.Collections.Generic.List<Vector3>
- {
- min,
- min + rotation * new Vector3(bounds.size.x, 0f, 0f),
- min + rotation * new Vector3(bounds.size.x, 0f, bounds.size.z),
- min + rotation * new Vector3(0f, 0f, bounds.size.z),
- min + rotation * new Vector3(0f, bounds.size.y, 0f),
- min + rotation * new Vector3(bounds.size.x, bounds.size.y, 0f),
- max,
- min + rotation * new Vector3(0f, bounds.size.y, bounds.size.z),
- min + rotation * new Vector3(bounds.size.x, 0f, bounds.size.z) / 2,
- max - rotation * new Vector3(bounds.size.x, 0f, bounds.size.z) / 2,
- };
- var visibleIdx = GetVisiblePoints(points.ToArray(), camera);
- points.Add(bounds.center);
- points.Add(bounds.center + _selectionRotation * _tempSelectionHandle);
- void DrawLine(Vector3[] line, float alpha = 1f)
- {
- UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.5f);
- UnityEditor.Handles.DrawAAPolyLine(10, line);
- UnityEditor.Handles.color = new Color(1f, 1f, 1f, 0.3f * alpha);
- UnityEditor.Handles.DrawAAPolyLine(4, line);
- }
- var visibleLines = new System.Collections.Generic.List<Vector3[]>();
- float ocludedAlpha = 0.5f;
- for (int i = 0; i < 8; ++i)
- {
- var visibleLine = visibleIdx.Contains(i) && visibleIdx.Contains(i + 4);
- if (i < 4)
- {
- var vLine = new Vector3[] { points[i],
- points[i] + rotation * new Vector3(0f, bounds.size.y, 0f) };
- if (visibleLine) visibleLines.Add(vLine);
- else DrawLine(vLine, ocludedAlpha);
- points.Add(vLine[0] + (vLine[1] - vLine[0]) / 2);
- }
- int nextI = ((i + 1) % 4) + 4 * (i / 4);
- visibleLine = visibleIdx.Contains(i) && visibleIdx.Contains(nextI);
- var hLine = new Vector3[] { points[i], points[nextI] };
- if (visibleLine) visibleLines.Add(hLine);
- else DrawLine(hLine, ocludedAlpha);
- var midpoint = hLine[0] + (hLine[1] - hLine[0]) / 2;
- points.Add(midpoint);
- if (i < 4) points.Add(midpoint + rotation * new Vector3(0f, bounds.size.y / 2, 0f));
- }
- foreach (var line in visibleLines) DrawLine(line);
- for (int i = 0; i < 8; ++i)
- {
- var alpha = visibleIdx.Contains(i) ? 1f : 0.3f;
- DrawDotHandleCap(points[i], alpha);
- }
- DrawDotHandleCap(points[11], 1);
- if(SelectionManager.topLevelSelection.Length == 1)
- {
- var pivotPosition = SelectionManager.topLevelSelection[0].transform.position;
- points.Add(pivotPosition);
- DrawDotHandleCap(pivotPosition, isPivot: true);
- }
- return points;
- }
- public static void SetSelectionOriginPosition() => _setSelectionOriginPosition = true;
- #region VISIBLE POINTS
- private static System.Collections.Generic.HashSet<int> GetVisiblePoints(Vector3[] points, Camera camera)
- {
- var resultSet = new System.Collections.Generic.HashSet<int>(GrahamScan(points));
- if (resultSet.Count == 6)
- {
- var ocluded = new System.Collections.Generic.List<int>();
- for (int i = 0; i < points.Length; ++i)
- {
- if (resultSet.Contains(i)) continue;
- ocluded.Add(i);
- }
- if ((ocluded[0] / 4 == ocluded[1] / 4) || (ocluded[1] == ocluded[0] + 4))
- return resultSet;
- var nearestIdx = camera.transform.InverseTransformPoint(points[ocluded[0]]).z
- < camera.transform.InverseTransformPoint(points[ocluded[1]]).z ? ocluded[0] : ocluded[1];
- resultSet.Add(nearestIdx);
- }
- return resultSet;
- }
- private static int[] GrahamScan(Vector3[] points)
- {
- var screenPoints = new System.Collections.Generic.List<BoxPoint>();
- for (int i = 0; i < points.Length; ++i)
- screenPoints.Add(new BoxPoint(i, UnityEditor.HandleUtility.WorldToGUIPoint(points[i])));
- var p0 = screenPoints[0];
- foreach (var value in screenPoints)
- {
- if (p0.point.y > value.point.y) p0 = value;
- }
- var order = new System.Collections.Generic.List<BoxPoint>();
- foreach (var point in screenPoints)
- {
- if (p0 != point) order.Add(point);
- }
- order = MergeSort(p0, order);
- var result = new System.Collections.Generic.List<BoxPoint>();
- result.Add(p0);
- result.Add(order[0]);
- result.Add(order[1]);
- order.RemoveAt(0);
- order.RemoveAt(0);
- foreach (var value in order) KeepLeft(result, value);
- var resultIdx = new int[result.Count];
- for (int i = 0; i < result.Count; ++i) resultIdx[i] = result[i];
- return resultIdx;
- }
- private class BoxPoint
- {
- public int idx = -1;
- public Vector2 point = Vector2.zero;
- public BoxPoint(int idx, Vector2 point) => (this.idx, this.point) = (idx, point);
- public override int GetHashCode()
- {
- int hashCode = 386348313;
- hashCode = hashCode * -1521134295 + idx.GetHashCode();
- hashCode = hashCode * -1521134295 + point.GetHashCode();
- return hashCode;
- }
- public bool Equals(BoxPoint other) => GetHashCode() == other.GetHashCode();
- public override bool Equals(object obj) => Equals(obj as BoxPoint);
- public static bool operator ==(BoxPoint l, BoxPoint r) => l.Equals(r);
- public static bool operator !=(BoxPoint l, BoxPoint r) => !l.Equals(r);
- public static implicit operator Vector2(BoxPoint value) => value.point;
- public static implicit operator int(BoxPoint value) => value.idx;
- }
- private static System.Collections.Generic.List<BoxPoint> MergeSort(BoxPoint p0,
- System.Collections.Generic.List<BoxPoint> pointList)
- {
- if (pointList.Count == 1) return pointList;
- var sortedList = new System.Collections.Generic.List<BoxPoint>();
- int middle = pointList.Count / 2;
- var leftArray = pointList.GetRange(0, middle);
- var rightArray = pointList.GetRange(middle, pointList.Count - middle);
- leftArray = MergeSort(p0, leftArray);
- rightArray = MergeSort(p0, rightArray);
- int leftptr = 0;
- int rightptr = 0;
- for (int i = 0; i < leftArray.Count + rightArray.Count; i++)
- {
- if (leftptr == leftArray.Count)
- {
- sortedList.Add(rightArray[rightptr]);
- rightptr++;
- }
- else if (rightptr == rightArray.Count)
- {
- sortedList.Add(leftArray[leftptr]);
- leftptr++;
- }
- else if (GetAngle(p0, leftArray[leftptr]) < GetAngle(p0, rightArray[rightptr]))
- {
- sortedList.Add(leftArray[leftptr]);
- leftptr++;
- }
- else
- {
- sortedList.Add(rightArray[rightptr]);
- rightptr++;
- }
- }
- return sortedList;
- }
- private static double GetAngle(Vector2 p1, Vector2 p2)
- {
- float xDiff = p2.x - p1.x;
- float yDiff = p2.y - p1.y;
- return Mathf.Atan2(yDiff, xDiff) * 180f / Mathf.PI;
- }
- private static void KeepLeft(System.Collections.Generic.List<BoxPoint> hull, BoxPoint point)
- {
- int turn(Vector2 p, Vector2 q, Vector2 r)
- => ((q.x - p.x) * (r.y - p.y) - (r.x - p.x) * (q.y - p.y)).CompareTo(0);
- while (hull.Count > 1 && turn(hull[hull.Count - 2], hull[hull.Count - 1], point) != 1)
- hull.RemoveAt(hull.Count - 1);
- if (hull.Count == 0 || hull[hull.Count - 1] != point) hull.Add(point);
- }
- #endregion
- }
- #endregion
- }
|