MirrorManager.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  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 UnityEngine;
  14. namespace PluginMaster
  15. {
  16. #region DATA & SETTINGS
  17. [System.Serializable]
  18. public class MirrorSettings : SelectionToolBase,
  19. IPaintToolSettings, ISerializationCallbackReceiver
  20. {
  21. public enum MirrorAction { TRANSFORM, CREATE}
  22. [SerializeField] private bool _reflectRotation = true;
  23. [SerializeField] private MirrorAction _action = MirrorAction.CREATE;
  24. [SerializeField] private bool _sameParentAsSource = true;
  25. [SerializeField] private Pose _mirrorPose = new Pose(Vector3.zero, Quaternion.LookRotation(Vector3.right, Vector3.up));
  26. [SerializeField] private bool _invertScale = false;
  27. private const string COMMAND_NAME = "Edit Mirror";
  28. public bool reflectRotation
  29. {
  30. get => _reflectRotation;
  31. set
  32. {
  33. if (_reflectRotation == value) return;
  34. _reflectRotation = value;
  35. DataChanged();
  36. }
  37. }
  38. public MirrorAction action
  39. {
  40. get => _action;
  41. set
  42. {
  43. if (_action == value) return;
  44. _action = value;
  45. DataChanged();
  46. }
  47. }
  48. public bool sameParentAsSource
  49. {
  50. get => _sameParentAsSource;
  51. set
  52. {
  53. if (_sameParentAsSource == value) return;
  54. _sameParentAsSource = value;
  55. DataChanged();
  56. }
  57. }
  58. public Pose mirrorPose => _mirrorPose;
  59. public Vector3 mirrorPosition
  60. {
  61. get => _mirrorPose.position;
  62. set
  63. {
  64. if (_mirrorPose.position == value) return;
  65. ToolProperties.RegisterUndo(COMMAND_NAME);
  66. _mirrorPose.position = value;
  67. DataChanged();
  68. }
  69. }
  70. public Quaternion mirrorRotation
  71. {
  72. get => _mirrorPose.rotation;
  73. set
  74. {
  75. if (_mirrorPose.rotation == value) return;
  76. ToolProperties.RegisterUndo(COMMAND_NAME);
  77. _mirrorPose.rotation = value;
  78. DataChanged();
  79. }
  80. }
  81. public bool invertScale
  82. {
  83. get => _invertScale;
  84. set
  85. {
  86. if (_invertScale == value) return;
  87. _invertScale = value;
  88. DataChanged();
  89. }
  90. }
  91. public override void Copy(IToolSettings other)
  92. {
  93. var otherMirrorSettings = other as MirrorSettings;
  94. if (otherMirrorSettings == null) return;
  95. base.Copy(other);
  96. _paintTool.Copy(otherMirrorSettings._paintTool);
  97. _reflectRotation = otherMirrorSettings.reflectRotation;
  98. _action = otherMirrorSettings._action;
  99. _sameParentAsSource = otherMirrorSettings._sameParentAsSource;
  100. _mirrorPose = otherMirrorSettings._mirrorPose;
  101. _invertScale = otherMirrorSettings._invertScale;
  102. }
  103. /*
  104. public override void Clone(ICloneableToolSettings clone)
  105. {
  106. if (clone == null || !(clone is MirrorSettings)) clone = new MirrorSettings();
  107. clone.Copy(this);
  108. }
  109. */
  110. public void OnBeforeSerialize() { }
  111. public void OnAfterDeserialize() => PWBIO.repaint = true;
  112. #region PAINT TOOL
  113. [SerializeField] private PaintToolSettings _paintTool = new PaintToolSettings();
  114. public Transform parent { get => _paintTool.parent; set => _paintTool.parent = value; }
  115. public bool overwritePrefabLayer { get => _paintTool.overwritePrefabLayer;
  116. set => _paintTool.overwritePrefabLayer = value; }
  117. public int layer { get => _paintTool.layer; set => _paintTool.layer = value; }
  118. public bool autoCreateParent { get => _paintTool.autoCreateParent; set => _paintTool.autoCreateParent = value; }
  119. public bool setSurfaceAsParent { get => _paintTool.setSurfaceAsParent; set => _paintTool.setSurfaceAsParent = value; }
  120. public bool createSubparentPerPalette
  121. {
  122. get => _paintTool.createSubparentPerPalette;
  123. set => _paintTool.createSubparentPerPalette = value;
  124. }
  125. public bool createSubparentPerTool
  126. {
  127. get => _paintTool.createSubparentPerTool;
  128. set => _paintTool.createSubparentPerTool = value;
  129. }
  130. public bool createSubparentPerBrush
  131. {
  132. get => _paintTool.createSubparentPerBrush;
  133. set => _paintTool.createSubparentPerBrush = value;
  134. }
  135. public bool createSubparentPerPrefab
  136. {
  137. get => _paintTool.createSubparentPerPrefab;
  138. set => _paintTool.createSubparentPerPrefab = value;
  139. }
  140. public bool overwriteBrushProperties {get => _paintTool.overwriteBrushProperties;
  141. set => _paintTool.overwriteBrushProperties = value; }
  142. public BrushSettings brushSettings => _paintTool.brushSettings;
  143. #endregion
  144. }
  145. [System.Serializable]
  146. public class MirrorManager : ToolManagerBase<MirrorSettings> { }
  147. #endregion
  148. #region PWBIO
  149. public static partial class PWBIO
  150. {
  151. private static bool _showMirrorHandles = true;
  152. private static GameObject _mirrorObject = null;
  153. private static Transform _mirroredTransform = null;
  154. public static void ResetMirrorState(bool askIfWantToSave = true)
  155. {
  156. if (askIfWantToSave && _paintStroke.Count > 0) DisplaySaveDialog(CreateMirroredObjects);
  157. }
  158. public static void InitializeMirrorPose()
  159. {
  160. if (_sceneViewCamera == null) return;
  161. MirrorManager.settings.mirrorPosition = Vector3.zero;
  162. var camRay = new Ray(_sceneViewCamera.transform.position, _sceneViewCamera.transform.forward);
  163. if (Physics.Raycast(camRay, out RaycastHit hit, float.MaxValue, -1))
  164. MirrorManager.settings.mirrorPosition = hit.point;
  165. if (GridRaycast(camRay, out RaycastHit gridHit))
  166. MirrorManager.settings.mirrorPosition = gridHit.point;
  167. MirrorManager.settings.mirrorPosition = SnapAndUpdateGridOrigin(MirrorManager.settings.mirrorPosition,
  168. SnapManager.settings.snappingEnabled, true, true, false, Vector3.down);
  169. MirrorManager.settings.mirrorRotation = Quaternion.LookRotation(Vector3.right, Vector3.up);
  170. _showMirrorHandles = true;
  171. }
  172. private static void MirrorDuringSceneGUI(UnityEditor.SceneView sceneView)
  173. {
  174. if (MirrorManager.settings.createTempColliders)
  175. PWBCore.CreateTempCollidersWithinFrustum(sceneView.camera);
  176. if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape)
  177. {
  178. if (_showMirrorHandles) _showMirrorHandles = false;
  179. else
  180. {
  181. ResetMirrorState(false);
  182. ToolManager.DeselectTool(false);
  183. }
  184. }
  185. DrawMirror();
  186. if (SelectionManager.topLevelSelection.Length == 0) return;
  187. PreviewMirror();
  188. MirrorInput();
  189. }
  190. private static void CreateMirroredObjects()
  191. {
  192. if (MirrorManager.settings.action == MirrorSettings.MirrorAction.CREATE)
  193. Paint(MirrorManager.settings, "Mirror");
  194. else
  195. {
  196. foreach (var item in _paintStroke)
  197. {
  198. UnityEditor.Undo.RecordObject(item.prefab.transform, "Mirror");
  199. item.prefab.transform.position = item.position;
  200. item.prefab.transform.rotation = item.rotation;
  201. }
  202. }
  203. ToolManager.DeselectTool();
  204. }
  205. private static void MirrorInput()
  206. {
  207. void Rotate90(Vector3 axis) => MirrorManager.settings.mirrorRotation *= Quaternion.AngleAxis(90, axis);
  208. if (Event.current.type == EventType.KeyDown && Event.current.control
  209. && Event.current.keyCode == KeyCode.UpArrow) Rotate90(Vector3.right);
  210. else if (Event.current.type == EventType.KeyDown && Event.current.control
  211. && Event.current.keyCode == KeyCode.DownArrow) Rotate90(Vector3.left);
  212. else if (Event.current.type == EventType.KeyDown && Event.current.control
  213. && Event.current.keyCode == KeyCode.RightArrow) Rotate90(Vector3.up);
  214. else if (Event.current.type == EventType.KeyDown && Event.current.control
  215. && Event.current.keyCode == KeyCode.LeftArrow) Rotate90(Vector3.down);
  216. else if (Event.current.type == EventType.KeyDown && Event.current.control
  217. && Event.current.keyCode == KeyCode.PageUp) Rotate90(Vector3.forward);
  218. else if (Event.current.type == EventType.KeyDown && Event.current.control
  219. && Event.current.keyCode == KeyCode.PageDown) Rotate90(Vector3.back);
  220. var confirm = Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return;
  221. if (!confirm) return;
  222. CreateMirroredObjects();
  223. }
  224. private static void DrawMirror()
  225. {
  226. UnityEditor.Handles.color = Color.yellow;
  227. var handleSize = UnityEditor.HandleUtility.GetHandleSize(Vector3.zero);
  228. UnityEditor.Handles.RectangleHandleCap(0, MirrorManager.settings.mirrorPosition
  229. - MirrorManager.settings.mirrorPose.forward * handleSize * 0.02f,
  230. MirrorManager.settings.mirrorRotation, handleSize, EventType.Repaint);
  231. UnityEditor.Handles.RectangleHandleCap(0, MirrorManager.settings.mirrorPosition
  232. + MirrorManager.settings.mirrorPose.forward * handleSize * 0.02f,
  233. MirrorManager.settings.mirrorRotation, handleSize, EventType.Repaint);
  234. UnityEditor.Handles.color = Color.black;
  235. UnityEditor.Handles.RectangleHandleCap(0, MirrorManager.settings.mirrorPosition,
  236. MirrorManager.settings.mirrorPose.rotation, handleSize * 1.2f, EventType.Repaint);
  237. if (_showMirrorHandles)
  238. {
  239. var prevPose = MirrorManager.settings.mirrorPose;
  240. MirrorManager.settings.mirrorPosition = UnityEditor.Handles.PositionHandle(MirrorManager.settings.mirrorPosition,
  241. MirrorManager.settings.mirrorRotation);
  242. MirrorManager.settings.mirrorPosition = SnapAndUpdateGridOrigin(MirrorManager.settings.mirrorPosition,
  243. SnapManager.settings.snappingEnabled, true, true, false, Vector3.down);
  244. MirrorManager.settings.mirrorRotation = UnityEditor.Handles.RotationHandle(MirrorManager.settings.mirrorRotation,
  245. MirrorManager.settings.mirrorPosition);
  246. if (prevPose != MirrorManager.settings.mirrorPose) ToolProperties.RepainWindow();
  247. }
  248. else
  249. {
  250. DrawDotHandleCap(MirrorManager.settings.mirrorPosition);
  251. var controlId = GUIUtility.GetControlID(FocusType.Passive);
  252. var distFromMouse = UnityEditor.HandleUtility.DistanceToRectangle(MirrorManager.settings.mirrorPosition,
  253. Quaternion.identity, 0f);
  254. UnityEditor.HandleUtility.AddControl(controlId, distFromMouse);
  255. if (UnityEditor.HandleUtility.nearestControl == controlId && Event.current.button == 0
  256. && Event.current.type == EventType.MouseDown) _showMirrorHandles = true;
  257. }
  258. }
  259. private static void PreviewMirror()
  260. {
  261. _paintStroke.Clear();
  262. if (_mirrorObject == null)
  263. {
  264. _mirrorObject = new GameObject("PluginMasterMirror");
  265. _mirrorObject.hideFlags = HideFlags.HideAndDontSave;
  266. _mirroredTransform = new GameObject("PluginMasterMirrorTempTransform").transform;
  267. _mirroredTransform.gameObject.hideFlags = HideFlags.HideAndDontSave;
  268. }
  269. var settings = MirrorManager.settings;
  270. _mirrorObject.transform.position = settings.mirrorPosition;
  271. _mirrorObject.transform.rotation = settings.mirrorRotation;
  272. foreach (var obj in SelectionManager.topLevelSelection)
  273. {
  274. if (obj == null) continue;
  275. _mirrorObject.transform.localScale = Vector3.one;
  276. _mirroredTransform.position = obj.transform.position;
  277. _mirroredTransform.rotation = obj.transform.rotation;
  278. _mirroredTransform.localScale = obj.transform.lossyScale;
  279. _mirroredTransform.SetParent(_mirrorObject.transform, true);
  280. _mirrorObject.transform.localScale = new Vector3(1f, 1f, -1f);
  281. if (!MirrorManager.settings.reflectRotation) _mirroredTransform.rotation = obj.transform.rotation;
  282. var previewScale = Vector3.one;
  283. var scale = _mirroredTransform.localScale;
  284. if (settings.invertScale)
  285. {
  286. scale *= -1;
  287. previewScale *= -1;
  288. var angle = new Vector3(180 - _mirroredTransform.rotation.eulerAngles.x,
  289. settings.reflectRotation
  290. ? _mirroredTransform.rotation.eulerAngles.y + 180
  291. : 180 - _mirroredTransform.rotation.eulerAngles.y,
  292. _mirroredTransform.rotation.eulerAngles.z);
  293. _mirroredTransform.rotation = Quaternion.Euler(angle);
  294. }
  295. Transform surface = null;
  296. if (settings.embedInSurface)
  297. {
  298. var TRS = Matrix4x4.TRS(_mirroredTransform.position, _mirroredTransform.rotation, previewScale);
  299. var bottomVertices = BoundsUtils.GetBottomVertices(obj.transform);
  300. var height = BoundsUtils.GetMagnitude(obj.transform) * 3;
  301. var surfceDistance = settings.embedAtPivotHeight
  302. ? GetPivotDistanceToSurfaceSigned(_mirroredTransform.position, height, true, true)
  303. : GetBottomDistanceToSurfaceSigned(bottomVertices, TRS, height, true, true);
  304. surfceDistance -= settings.surfaceDistance;
  305. _mirroredTransform.position += new Vector3(0f, -surfceDistance, 0f);
  306. if (settings.rotateToTheSurface)
  307. {
  308. var down = _mirroredTransform.rotation * Vector3.down;
  309. var ray = new Ray(_mirroredTransform.position - down * height, down);
  310. if (MouseRaycast(ray, out RaycastHit hitInfo, out GameObject collider,
  311. float.MaxValue, -1, true, true))
  312. {
  313. var tangent = Vector3.Cross(hitInfo.normal, Vector3.left);
  314. if (tangent.sqrMagnitude < 0.000001) tangent = Vector3.Cross(hitInfo.normal, Vector3.back);
  315. tangent = tangent.normalized;
  316. _mirroredTransform.rotation = Quaternion.LookRotation(tangent, hitInfo.normal);
  317. var colObj = PWBCore.GetGameObjectFromTempCollider(collider);
  318. if (colObj != null) surface = colObj.transform;
  319. }
  320. }
  321. }
  322. var matrix = Matrix4x4.TRS(_mirroredTransform.position, _mirroredTransform.rotation, previewScale)
  323. * Matrix4x4.Rotate(Quaternion.Inverse(obj.transform.rotation))
  324. * Matrix4x4.Translate(-obj.transform.position);
  325. var layer = settings.overwritePrefabLayer ? settings.layer : obj.layer;
  326. var reverseTriagles = scale.x * scale.y * scale.z < 0;
  327. PreviewBrushItem(obj, matrix, layer, _sceneViewCamera, false, reverseTriagles, false, false);
  328. var parent = settings.sameParentAsSource
  329. ? obj.transform.parent : GetParent(settings, obj.name, false, null);
  330. _paintStroke.Add(new PaintStrokeItem(obj, _mirroredTransform.position,
  331. _mirroredTransform.rotation, scale, layer, parent, null, false, false));
  332. }
  333. }
  334. }
  335. #endregion
  336. }