A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using UnityEditor.U2D.Layout;
5using UnityEditor.U2D.Sprites;
6using UnityEngine;
7
8namespace UnityEditor.U2D.Animation
9{
10 internal class SelectionTool : BaseTool
11 {
12 bool m_ForceSelectedToSpriteEditor = false;
13 int m_LastMouseButtonDown = -1;
14
15 public event Func<bool> CanSelect = () => true;
16 List<SpriteCache> m_Sprites;
17 public ISpriteEditor spriteEditor { get; set; }
18
19 SpriteCache selectedSprite
20 {
21 get => skinningCache.selectedSprite;
22 set
23 {
24 if (selectedSprite != value)
25 {
26 skinningCache.vertexSelection.Clear();
27
28 if (skinningCache.mode == SkinningMode.SpriteSheet)
29 {
30 skinningCache.skeletonSelection.Clear();
31 skinningCache.events.boneSelectionChanged.Invoke();
32 }
33
34 skinningCache.selectedSprite = value;
35 SetToSpriteEditor();
36 skinningCache.events.selectedSpriteChanged.Invoke(value);
37 }
38 }
39 }
40
41 string selectedSpriteAssetID
42 {
43 get
44 {
45 var sprite = Selection.activeObject as Sprite;
46
47 if (sprite != null)
48 return sprite.GetSpriteID().ToString();
49
50 return "";
51 }
52 }
53
54 protected override void OnAfterDeserialize()
55 {
56 m_ForceSelectedToSpriteEditor = true;
57 }
58
59 public override void Initialize(LayoutOverlay layoutOverlay)
60 {
61 m_Sprites = new List<SpriteCache>(skinningCache.GetSprites());
62 SetFromSpriteEditor();
63 }
64
65 protected override void OnActivate()
66 {
67 SetToSpriteEditor();
68 skinningCache.events.selectedSpriteChanged.AddListener(OnSpriteSelectionChange);
69 Selection.selectionChanged -= OnSelectionChanged;
70 Selection.selectionChanged += OnSelectionChanged;
71 }
72
73 protected override void OnDeactivate()
74 {
75 skinningCache.events.selectedSpriteChanged.RemoveListener(OnSpriteSelectionChange);
76 Selection.selectionChanged -= OnSelectionChanged;
77 }
78
79 private void OnSpriteSelectionChange(SpriteCache sprite)
80 {
81 skinningCache.events.selectedSpriteChanged.RemoveListener(OnSpriteSelectionChange);
82 selectedSprite = sprite;
83 skinningCache.events.selectedSpriteChanged.AddListener(OnSpriteSelectionChange);
84 }
85
86 void OnSelectionChanged()
87 {
88 if (m_ForceSelectedToSpriteEditor)
89 {
90 SetToSpriteEditor();
91 m_ForceSelectedToSpriteEditor = false;
92 }
93 else
94 {
95 using (skinningCache.UndoScope(TextContent.selectionChange))
96 {
97 SetFromSpriteEditor();
98 }
99 }
100 }
101
102 void SetFromSpriteEditor()
103 {
104 if (selectedSprite == null)
105 selectedSprite = skinningCache.GetSprite(selectedSpriteAssetID);
106 spriteEditor.RequestRepaint();
107 }
108
109 void SetToSpriteEditor()
110 {
111 var id = "";
112
113 if (selectedSprite != null)
114 id = selectedSprite.id;
115
116 spriteEditor.selectedSpriteRect = new SpriteRect() { spriteID = new GUID(id) };
117 }
118
119 protected override void OnGUI()
120 {
121 HandleSpriteSelection();
122 }
123
124 void HandleSpriteSelection()
125 {
126 Debug.Assert(Event.current != null);
127
128 if (Event.current.type == EventType.MouseDown)
129 {
130 if (IsSelectionRequested())
131 {
132 var mousePosition = Handles.inverseMatrix.MultiplyPoint(Event.current.mousePosition);
133 var newSelected = TrySelect(mousePosition);
134 if (selectedSprite != newSelected)
135 {
136 using (skinningCache.UndoScope(TextContent.selectionChange))
137 {
138 selectedSprite = newSelected;
139 }
140
141 Event.current.Use();
142 }
143 }
144 else
145 m_LastMouseButtonDown = Event.current.button;
146 }
147 }
148
149 SpriteCache TrySelect(Vector2 mousePosition)
150 {
151 m_Sprites.Remove(selectedSprite);
152
153 if (selectedSprite != null)
154 m_Sprites.Add(selectedSprite);
155
156 var currentSelectedIndex = m_Sprites.FindIndex(x => x == selectedSprite) + 1;
157 var notVisiblePart = skinningCache.hasCharacter && skinningCache.mode == SkinningMode.Character
158 ? skinningCache.character.parts.Where(x => !x.isVisible).Select(x => x.sprite)
159 : new SpriteCache[0];
160 for (int index = 0; index < m_Sprites.Count; ++index)
161 {
162 var sprite = m_Sprites[(currentSelectedIndex + index) % m_Sprites.Count];
163 var meshPreview = sprite.GetMeshPreview();
164 if (notVisiblePart.Contains(sprite))
165 continue;
166
167 Debug.Assert(meshPreview != null);
168
169 var spritePosition = sprite.GetLocalToWorldMatrixFromMode().MultiplyPoint3x4(Vector3.zero);
170 var ray = new Ray((Vector3)mousePosition - spritePosition + Vector3.back, Vector3.forward);
171 var bounds = meshPreview.mesh.bounds;
172
173 if (sprite.GetMesh().indices.Length >= 3)
174 {
175 if (bounds.IntersectRay(ray))
176 {
177 var mesh = sprite.GetMesh();
178
179 Debug.Assert(mesh != null);
180
181 var indices = mesh.indices;
182 for (var i = 0; i < indices.Length; i += 3)
183 {
184 var p1 = meshPreview.vertices[indices[i]];
185 var p2 = meshPreview.vertices[indices[i + 1]];
186 var p3 = meshPreview.vertices[indices[i + 2]];
187
188 if (MathUtility.Intersect(p1, p2, p3, ray))
189 return sprite;
190 }
191 }
192 }
193 else
194 {
195 if (meshPreview.defaultMesh.bounds.IntersectRay(ray))
196 {
197 return sprite;
198 }
199 }
200 }
201
202 return null;
203 }
204
205 bool IsSelectionRequested()
206 {
207 return Event.current.button == 0 && m_LastMouseButtonDown == 0 && GUIUtility.hotControl == 0 &&
208 !Event.current.alt && Event.current.clickCount == 2 && CanSelect();
209 }
210 }
211}