A game about forced loneliness, made by TACStudios
1using System;
2using Unity.Mathematics;
3using UnityEngine;
4
5namespace UnityEditor.U2D.Animation
6{
7 internal class SpriteMeshController
8 {
9 const float k_SnapDistance = 10f;
10
11 struct EdgeIntersectionResult
12 {
13 public int startVertexIndex;
14 public int endVertexIndex;
15 public int intersectEdgeIndex;
16 public Vector2 endPosition;
17 }
18
19 SpriteMeshDataController m_SpriteMeshDataController = new();
20 EdgeIntersectionResult m_EdgeIntersectionResult;
21
22 public ISpriteMeshView spriteMeshView { get; set; }
23 public BaseSpriteMeshData spriteMeshData { get; set; }
24 public ISelection<int> selection { get; set; }
25 public ICacheUndo cacheUndo { get; set; }
26 public ITriangulator triangulator { get; set; }
27
28 public bool disable { get; set; }
29 public Rect frame { get; set; }
30
31 public void OnGUI()
32 {
33 m_SpriteMeshDataController.spriteMeshData = spriteMeshData;
34
35 Debug.Assert(spriteMeshView != null);
36 Debug.Assert(spriteMeshData != null);
37 Debug.Assert(selection != null);
38 Debug.Assert(cacheUndo != null);
39
40 ValidateSelectionValues();
41
42 spriteMeshView.selection = selection;
43 spriteMeshView.frame = frame;
44
45 EditorGUI.BeginDisabledGroup(disable);
46
47 spriteMeshView.BeginLayout();
48
49 if (spriteMeshView.CanLayout())
50 {
51 LayoutVertices();
52 LayoutEdges();
53 }
54
55 spriteMeshView.EndLayout();
56
57 if (spriteMeshView.CanRepaint())
58 {
59 DrawEdges();
60
61 if (GUI.enabled)
62 {
63 PreviewCreateVertex();
64 PreviewCreateEdge();
65 PreviewSplitEdge();
66 }
67
68 DrawVertices();
69 }
70
71
72 HandleSplitEdge();
73 HandleCreateEdge();
74 HandleCreateVertex();
75
76 EditorGUI.EndDisabledGroup();
77
78 HandleSelectVertex();
79 HandleSelectEdge();
80
81 EditorGUI.BeginDisabledGroup(disable);
82
83 HandleMoveVertexAndEdge();
84
85 EditorGUI.EndDisabledGroup();
86
87 EditorGUI.BeginDisabledGroup(disable);
88
89 HandleRemoveVertices();
90
91 spriteMeshView.DoRepaint();
92
93 EditorGUI.EndDisabledGroup();
94 }
95
96 void ValidateSelectionValues()
97 {
98 foreach (var index in selection.elements)
99 {
100 if (index >= spriteMeshData.vertexCount)
101 {
102 selection.Clear();
103 break;
104 }
105 }
106 }
107
108 void LayoutVertices()
109 {
110 for (var i = 0; i < spriteMeshData.vertexCount; i++)
111 {
112 spriteMeshView.LayoutVertex(spriteMeshData.vertices[i], i);
113 }
114 }
115
116 void LayoutEdges()
117 {
118 for (var i = 0; i < spriteMeshData.edges.Length; i++)
119 {
120 var edge = spriteMeshData.edges[i];
121 var startPosition = spriteMeshData.vertices[edge.x];
122 var endPosition = spriteMeshData.vertices[edge.y];
123
124 spriteMeshView.LayoutEdge(startPosition, endPosition, i);
125 }
126 }
127
128 void DrawEdges()
129 {
130 UpdateEdgeIntersection();
131
132 spriteMeshView.BeginDrawEdges();
133
134 for (var i = 0; i < spriteMeshData.edges.Length; ++i)
135 {
136 if (SkipDrawEdge(i))
137 continue;
138
139 var edge = spriteMeshData.edges[i];
140 var startPosition = spriteMeshData.vertices[edge.x];
141 var endPosition = spriteMeshData.vertices[edge.y];
142
143 if (selection.Contains(edge.x) && selection.Contains(edge.y))
144 spriteMeshView.DrawEdgeSelected(startPosition, endPosition);
145 else
146 spriteMeshView.DrawEdge(startPosition, endPosition);
147 }
148
149 if (spriteMeshView.IsActionActive(MeshEditorAction.SelectEdge))
150 {
151 var hoveredEdge = spriteMeshData.edges[spriteMeshView.hoveredEdge];
152 var startPosition = spriteMeshData.vertices[hoveredEdge.x];
153 var endPosition = spriteMeshData.vertices[hoveredEdge.y];
154
155 spriteMeshView.DrawEdgeHovered(startPosition, endPosition);
156 }
157
158 spriteMeshView.EndDrawEdges();
159 }
160
161 bool SkipDrawEdge(int edgeIndex)
162 {
163 if (GUI.enabled == false)
164 return false;
165
166 return edgeIndex == -1 ||
167 spriteMeshView.hoveredEdge == edgeIndex && spriteMeshView.IsActionActive(MeshEditorAction.SelectEdge) ||
168 spriteMeshView.hoveredEdge == edgeIndex && spriteMeshView.IsActionActive(MeshEditorAction.CreateVertex) ||
169 spriteMeshView.closestEdge == edgeIndex && spriteMeshView.IsActionActive(MeshEditorAction.SplitEdge) ||
170 edgeIndex == m_EdgeIntersectionResult.intersectEdgeIndex && spriteMeshView.IsActionActive(MeshEditorAction.CreateEdge);
171 }
172
173 void PreviewCreateVertex()
174 {
175 if (spriteMeshView.mode == SpriteMeshViewMode.CreateVertex &&
176 spriteMeshView.IsActionActive(MeshEditorAction.CreateVertex))
177 {
178 var clampedMousePos = ClampToFrame(spriteMeshView.mouseWorldPosition);
179
180 if (spriteMeshView.hoveredEdge != -1)
181 {
182 var edge = spriteMeshData.edges[spriteMeshView.hoveredEdge];
183
184 spriteMeshView.BeginDrawEdges();
185
186 spriteMeshView.DrawEdge(spriteMeshData.vertices[edge.x], clampedMousePos);
187 spriteMeshView.DrawEdge(spriteMeshData.vertices[edge.y], clampedMousePos);
188
189 spriteMeshView.EndDrawEdges();
190 }
191
192 spriteMeshView.DrawVertex(clampedMousePos);
193 }
194 }
195
196 void PreviewCreateEdge()
197 {
198 if (!spriteMeshView.IsActionActive(MeshEditorAction.CreateEdge))
199 return;
200
201 spriteMeshView.BeginDrawEdges();
202
203 spriteMeshView.DrawEdge(spriteMeshData.vertices[m_EdgeIntersectionResult.startVertexIndex], m_EdgeIntersectionResult.endPosition);
204
205 if (m_EdgeIntersectionResult.intersectEdgeIndex != -1)
206 {
207 var intersectingEdge = spriteMeshData.edges[m_EdgeIntersectionResult.intersectEdgeIndex];
208 spriteMeshView.DrawEdge(spriteMeshData.vertices[intersectingEdge.x], m_EdgeIntersectionResult.endPosition);
209 spriteMeshView.DrawEdge(spriteMeshData.vertices[intersectingEdge.y], m_EdgeIntersectionResult.endPosition);
210 }
211
212 spriteMeshView.EndDrawEdges();
213
214 if (m_EdgeIntersectionResult.endVertexIndex == -1)
215 spriteMeshView.DrawVertex(m_EdgeIntersectionResult.endPosition);
216 }
217
218 void PreviewSplitEdge()
219 {
220 if (!spriteMeshView.IsActionActive(MeshEditorAction.SplitEdge))
221 return;
222
223 var clampedMousePos = ClampToFrame(spriteMeshView.mouseWorldPosition);
224
225 var closestEdge = spriteMeshData.edges[spriteMeshView.closestEdge];
226
227 spriteMeshView.BeginDrawEdges();
228
229 spriteMeshView.DrawEdge(spriteMeshData.vertices[closestEdge.x], clampedMousePos);
230 spriteMeshView.DrawEdge(spriteMeshData.vertices[closestEdge.y], clampedMousePos);
231
232 spriteMeshView.EndDrawEdges();
233
234 spriteMeshView.DrawVertex(clampedMousePos);
235 }
236
237 void DrawVertices()
238 {
239 for (var i = 0; i < spriteMeshData.vertexCount; i++)
240 {
241 var position = spriteMeshData.vertices[i];
242
243 if (selection.Contains(i))
244 spriteMeshView.DrawVertexSelected(position);
245 else if (i == spriteMeshView.hoveredVertex && spriteMeshView.IsActionHot(MeshEditorAction.None))
246 spriteMeshView.DrawVertexHovered(position);
247 else
248 spriteMeshView.DrawVertex(position);
249 }
250 }
251
252 void HandleSelectVertex()
253 {
254 if (spriteMeshView.DoSelectVertex(out var additive))
255 SelectVertex(spriteMeshView.hoveredVertex, additive);
256 }
257
258 void HandleSelectEdge()
259 {
260 if (spriteMeshView.DoSelectEdge(out var additive))
261 SelectEdge(spriteMeshView.hoveredEdge, additive);
262 }
263
264 void HandleMoveVertexAndEdge()
265 {
266 if (selection.Count == 0)
267 return;
268
269 if (spriteMeshView.DoMoveVertex(out var finalDeltaPos) || spriteMeshView.DoMoveEdge(out finalDeltaPos))
270 {
271 var selectionArray = selection.elements;
272
273 finalDeltaPos = MathUtility.MoveRectInsideFrame(CalculateRectFromSelection(), frame, finalDeltaPos);
274 var movedVertexSelection = GetMovedVertexSelection(in selectionArray, spriteMeshData.vertices, finalDeltaPos);
275
276 if (IsMovedEdgeIntersectingWithOtherEdge(in selectionArray, in movedVertexSelection, spriteMeshData.edges, spriteMeshData.vertices))
277 return;
278 if (IsMovedVertexIntersectingWithOutline(in selectionArray, in movedVertexSelection, spriteMeshData.outlineEdges, spriteMeshData.vertices))
279 return;
280
281 cacheUndo.BeginUndoOperation(TextContent.moveVertices);
282 MoveSelectedVertices(in movedVertexSelection);
283 }
284 }
285
286 void HandleCreateVertex()
287 {
288 if (spriteMeshView.DoCreateVertex())
289 {
290 var position = ClampToFrame(spriteMeshView.mouseWorldPosition);
291 var edgeIndex = spriteMeshView.hoveredEdge;
292 if (spriteMeshView.hoveredEdge != -1)
293 CreateVertex(position, edgeIndex);
294 else if (m_SpriteMeshDataController.FindTriangle(position, out var indices, out var barycentricCoords))
295 CreateVertex(position, indices, barycentricCoords);
296 }
297 }
298
299 void HandleSplitEdge()
300 {
301 if (spriteMeshView.DoSplitEdge())
302 SplitEdge(ClampToFrame(spriteMeshView.mouseWorldPosition), spriteMeshView.closestEdge);
303 }
304
305 void HandleCreateEdge()
306 {
307 if (spriteMeshView.DoCreateEdge())
308 {
309 var clampedMousePosition = ClampToFrame(spriteMeshView.mouseWorldPosition);
310 var edgeIntersectionResult = CalculateEdgeIntersection(selection.activeElement, spriteMeshView.hoveredVertex, spriteMeshView.hoveredEdge, clampedMousePosition);
311
312 if (edgeIntersectionResult.endVertexIndex != -1)
313 {
314 CreateEdge(selection.activeElement, edgeIntersectionResult.endVertexIndex);
315 }
316 else
317 {
318 if (edgeIntersectionResult.intersectEdgeIndex != -1)
319 {
320 CreateVertex(edgeIntersectionResult.endPosition, edgeIntersectionResult.intersectEdgeIndex);
321 CreateEdge(selection.activeElement, spriteMeshData.vertexCount - 1);
322 }
323 else if (m_SpriteMeshDataController.FindTriangle(edgeIntersectionResult.endPosition, out var indices, out var barycentricCoords))
324 {
325 CreateVertex(edgeIntersectionResult.endPosition, indices, barycentricCoords);
326 CreateEdge(selection.activeElement, spriteMeshData.vertexCount - 1);
327 }
328 }
329 }
330 }
331
332 void HandleRemoveVertices()
333 {
334 if (spriteMeshView.DoRemove())
335 RemoveSelectedVertices();
336 }
337
338 void CreateVertex(Vector2 position, Vector3Int indices, Vector3 barycentricCoords)
339 {
340 var bw1 = spriteMeshData.vertexWeights[indices.x];
341 var bw2 = spriteMeshData.vertexWeights[indices.y];
342 var bw3 = spriteMeshData.vertexWeights[indices.z];
343
344 var result = new EditableBoneWeight();
345
346 foreach (var channel in bw1)
347 {
348 if (!channel.enabled)
349 continue;
350
351 var weight = channel.weight * barycentricCoords.x;
352 if (weight > 0f)
353 result.AddChannel(channel.boneIndex, weight, true);
354 }
355
356 foreach (var channel in bw2)
357 {
358 if (!channel.enabled)
359 continue;
360
361 var weight = channel.weight * barycentricCoords.y;
362 if (weight > 0f)
363 result.AddChannel(channel.boneIndex, weight, true);
364 }
365
366 foreach (var channel in bw3)
367 {
368 if (!channel.enabled)
369 continue;
370
371 var weight = channel.weight * barycentricCoords.z;
372 if (weight > 0f)
373 result.AddChannel(channel.boneIndex, weight, true);
374 }
375
376 result.UnifyChannelsWithSameBoneIndex();
377 result.FilterChannels(0f);
378 result.Clamp(4, true);
379
380 var boneWeight = result.ToBoneWeight(true);
381
382 cacheUndo.BeginUndoOperation(TextContent.createVertex);
383
384 m_SpriteMeshDataController.CreateVertex(position, -1);
385 spriteMeshData.vertexWeights[spriteMeshData.vertexCount - 1].SetFromBoneWeight(boneWeight);
386 Triangulate();
387 }
388
389 void CreateVertex(Vector2 position, int edgeIndex)
390 {
391 var edge = spriteMeshData.edges[edgeIndex];
392 var pos1 = spriteMeshData.vertices[edge.x];
393 var pos2 = spriteMeshData.vertices[edge.y];
394 var dir1 = (position - pos1);
395 var dir2 = (pos2 - pos1);
396 var t = Vector2.Dot(dir1, dir2.normalized) / dir2.magnitude;
397 t = Mathf.Clamp01(t);
398 var bw1 = spriteMeshData.vertexWeights[edge.x].ToBoneWeight(true);
399 var bw2 = spriteMeshData.vertexWeights[edge.y].ToBoneWeight(true);
400
401 var boneWeight = EditableBoneWeightUtility.Lerp(bw1, bw2, t);
402
403 cacheUndo.BeginUndoOperation(TextContent.createVertex);
404
405 m_SpriteMeshDataController.CreateVertex(position, edgeIndex);
406 spriteMeshData.vertexWeights[spriteMeshData.vertexCount - 1].SetFromBoneWeight(boneWeight);
407 Triangulate();
408 }
409
410 void SelectVertex(int index, bool additiveToggle)
411 {
412 if (index < 0)
413 throw new ArgumentException("Index out of range");
414
415 var selected = selection.Contains(index);
416 if (selected)
417 {
418 if (additiveToggle)
419 {
420 cacheUndo.BeginUndoOperation(TextContent.selection);
421 selection.Select(index, false);
422 }
423 }
424 else
425 {
426 cacheUndo.BeginUndoOperation(TextContent.selection);
427
428 if (!additiveToggle)
429 ClearSelection();
430
431 selection.Select(index, true);
432 }
433
434 cacheUndo.IncrementCurrentGroup();
435 }
436
437 void SelectEdge(int index, bool additiveToggle)
438 {
439 Debug.Assert(index >= 0);
440
441 var edge = spriteMeshData.edges[index];
442
443 cacheUndo.BeginUndoOperation(TextContent.selection);
444
445 var selected = selection.Contains(edge.x) && selection.Contains(edge.y);
446 if (selected)
447 {
448 if (additiveToggle)
449 {
450 selection.Select(edge.x, false);
451 selection.Select(edge.y, false);
452 }
453 }
454 else
455 {
456 if (!additiveToggle)
457 ClearSelection();
458
459 selection.Select(edge.x, true);
460 selection.Select(edge.y, true);
461 }
462
463 cacheUndo.IncrementCurrentGroup();
464 }
465
466 void ClearSelection()
467 {
468 cacheUndo.BeginUndoOperation(TextContent.selection);
469 selection.Clear();
470 }
471
472 void MoveSelectedVertices(in Vector2[] movedVertices)
473 {
474 for (var i = 0; i < selection.Count; ++i)
475 {
476 var index = selection.elements[i];
477 spriteMeshData.vertices[index] = movedVertices[i];
478 }
479
480 Triangulate();
481 }
482
483 void CreateEdge(int fromVertexIndex, int toVertexIndex)
484 {
485 cacheUndo.BeginUndoOperation(TextContent.createEdge);
486
487 m_SpriteMeshDataController.CreateEdge(fromVertexIndex, toVertexIndex);
488 Triangulate();
489 ClearSelection();
490 selection.Select(toVertexIndex, true);
491
492 cacheUndo.IncrementCurrentGroup();
493 }
494
495 void SplitEdge(Vector2 position, int edgeIndex)
496 {
497 cacheUndo.BeginUndoOperation(TextContent.splitEdge);
498
499 CreateVertex(position, edgeIndex);
500
501 cacheUndo.IncrementCurrentGroup();
502 }
503
504 bool IsEdgeSelected()
505 {
506 if (selection.Count != 2)
507 return false;
508
509 var indices = selection.elements;
510
511 var index1 = indices[0];
512 var index2 = indices[1];
513
514 var edge = new int2(index1, index2);
515 return spriteMeshData.edges.ContainsAny(edge);
516 }
517
518 void RemoveSelectedVertices()
519 {
520 cacheUndo.BeginUndoOperation(IsEdgeSelected() ? TextContent.removeEdge : TextContent.removeVertices);
521
522 var verticesToRemove = selection.elements;
523
524 var noOfVertsToDelete = verticesToRemove.Length;
525 var noOfVertsInMesh = m_SpriteMeshDataController.spriteMeshData.vertexCount;
526 var shouldClearMesh = (noOfVertsInMesh - noOfVertsToDelete) < 3;
527
528 if (shouldClearMesh)
529 {
530 m_SpriteMeshDataController.spriteMeshData.Clear();
531 m_SpriteMeshDataController.CreateQuad();
532 }
533 else
534 m_SpriteMeshDataController.RemoveVertex(verticesToRemove);
535
536 Triangulate();
537
538 selection.Clear();
539 }
540
541 void Triangulate()
542 {
543 m_SpriteMeshDataController.Triangulate(triangulator);
544 m_SpriteMeshDataController.SortTrianglesByDepth();
545 }
546
547 Vector2 ClampToFrame(Vector2 position)
548 {
549 return MathUtility.ClampPositionToRect(position, frame);
550 }
551
552 Rect CalculateRectFromSelection()
553 {
554 var rect = new Rect();
555
556 var min = new Vector2(float.MaxValue, float.MaxValue);
557 var max = new Vector2(float.MinValue, float.MinValue);
558
559 var indices = selection.elements;
560
561 foreach (var index in indices)
562 {
563 var v = spriteMeshData.vertices[index];
564
565 min.x = Mathf.Min(min.x, v.x);
566 min.y = Mathf.Min(min.y, v.y);
567
568 max.x = Mathf.Max(max.x, v.x);
569 max.y = Mathf.Max(max.y, v.y);
570 }
571
572 rect.min = min;
573 rect.max = max;
574
575 return rect;
576 }
577
578 void UpdateEdgeIntersection()
579 {
580 if (selection.Count == 1)
581 m_EdgeIntersectionResult = CalculateEdgeIntersection(selection.activeElement, spriteMeshView.hoveredVertex, spriteMeshView.hoveredEdge, ClampToFrame(spriteMeshView.mouseWorldPosition));
582 }
583
584 EdgeIntersectionResult CalculateEdgeIntersection(int vertexIndex, int hoveredVertexIndex, int hoveredEdgeIndex, Vector2 targetPosition)
585 {
586 Debug.Assert(vertexIndex >= 0);
587
588 var edgeIntersection = new EdgeIntersectionResult
589 {
590 startVertexIndex = vertexIndex,
591 endVertexIndex = hoveredVertexIndex,
592 endPosition = targetPosition,
593 intersectEdgeIndex = -1
594 };
595
596 var startPoint = spriteMeshData.vertices[edgeIntersection.startVertexIndex];
597
598 var intersectsEdge = false;
599 var lastIntersectingEdgeIndex = -1;
600
601 do
602 {
603 lastIntersectingEdgeIndex = edgeIntersection.intersectEdgeIndex;
604
605 if (intersectsEdge)
606 {
607 var dir = edgeIntersection.endPosition - startPoint;
608 edgeIntersection.endPosition += dir.normalized * 10f;
609 }
610
611 intersectsEdge = SegmentIntersectsEdge(startPoint, edgeIntersection.endPosition, vertexIndex, ref edgeIntersection.endPosition, out edgeIntersection.intersectEdgeIndex);
612
613 //if we are hovering a vertex and intersect an edge indexing it we forget about the intersection
614 var edges = spriteMeshData.edges;
615 var edge = intersectsEdge ? edges[edgeIntersection.intersectEdgeIndex] : default;
616 if (intersectsEdge && (edge.x == edgeIntersection.endVertexIndex || edge.y == edgeIntersection.endVertexIndex))
617 {
618 edgeIntersection.intersectEdgeIndex = -1;
619 intersectsEdge = false;
620 edgeIntersection.endPosition = spriteMeshData.vertices[edgeIntersection.endVertexIndex];
621 }
622
623 if (intersectsEdge)
624 {
625 edgeIntersection.endVertexIndex = -1;
626
627 var intersectingEdge = spriteMeshData.edges[edgeIntersection.intersectEdgeIndex];
628 var newPointScreen = spriteMeshView.WorldToScreen(edgeIntersection.endPosition);
629 var edgeV1 = spriteMeshView.WorldToScreen(spriteMeshData.vertices[intersectingEdge.x]);
630 var edgeV2 = spriteMeshView.WorldToScreen(spriteMeshData.vertices[intersectingEdge.y]);
631
632 if ((newPointScreen - edgeV1).magnitude <= k_SnapDistance)
633 edgeIntersection.endVertexIndex = intersectingEdge.x;
634 else if ((newPointScreen - edgeV2).magnitude <= k_SnapDistance)
635 edgeIntersection.endVertexIndex = intersectingEdge.y;
636
637 if (edgeIntersection.endVertexIndex != -1)
638 {
639 edgeIntersection.intersectEdgeIndex = -1;
640 intersectsEdge = false;
641 edgeIntersection.endPosition = spriteMeshData.vertices[edgeIntersection.endVertexIndex];
642 }
643 }
644 } while (intersectsEdge && lastIntersectingEdgeIndex != edgeIntersection.intersectEdgeIndex);
645
646 edgeIntersection.intersectEdgeIndex = intersectsEdge ? edgeIntersection.intersectEdgeIndex : hoveredEdgeIndex;
647
648 if (edgeIntersection.endVertexIndex != -1 && !intersectsEdge)
649 edgeIntersection.endPosition = spriteMeshData.vertices[edgeIntersection.endVertexIndex];
650
651 return edgeIntersection;
652 }
653
654 bool SegmentIntersectsEdge(Vector2 p1, Vector2 p2, int ignoreIndex, ref Vector2 point, out int intersectingEdgeIndex)
655 {
656 intersectingEdgeIndex = -1;
657
658 var sqrDistance = float.MaxValue;
659
660 for (var i = 0; i < spriteMeshData.edges.Length; i++)
661 {
662 var edge = spriteMeshData.edges[i];
663 var v1 = spriteMeshData.vertices[edge.x];
664 var v2 = spriteMeshData.vertices[edge.y];
665 var pointTmp = Vector2.zero;
666
667 if (edge.x != ignoreIndex && edge.y != ignoreIndex &&
668 MathUtility.SegmentIntersection(p1, p2, v1, v2, ref pointTmp))
669 {
670 var sqrMagnitude = (pointTmp - p1).sqrMagnitude;
671 if (sqrMagnitude < sqrDistance)
672 {
673 sqrDistance = sqrMagnitude;
674 intersectingEdgeIndex = i;
675 point = pointTmp;
676 }
677 }
678 }
679
680 return intersectingEdgeIndex != -1;
681 }
682
683
684 static Vector2[] GetMovedVertexSelection(in int[] selection, in Vector2[] vertices, Vector2 deltaPosition)
685 {
686 var movedVertices = new Vector2[selection.Length];
687 for (var i = 0; i < selection.Length; i++)
688 {
689 var index = selection[i];
690 movedVertices[i] = vertices[index] + deltaPosition;
691 }
692
693 return movedVertices;
694 }
695
696 static bool IsMovedEdgeIntersectingWithOtherEdge(in int[] selection, in Vector2[] movedVertices, in int2[] meshEdges, in Vector2[] meshVertices)
697 {
698 var edgeCount = meshEdges.Length;
699 var edgeIntersectionPoint = Vector2.zero;
700
701 for (var i = 0; i < edgeCount; i++)
702 {
703 var selectionIndex = FindSelectionIndexFromEdge(selection, meshEdges[i]);
704 if (selectionIndex.x == -1 && selectionIndex.y == -1)
705 continue;
706
707 var edgeStart = selectionIndex.x != -1 ? movedVertices[selectionIndex.x] : meshVertices[meshEdges[i].x];
708 var edgeEnd = selectionIndex.y != -1 ? movedVertices[selectionIndex.y] : meshVertices[meshEdges[i].y];
709
710 for (var o = 0; o < edgeCount; o++)
711 {
712 if (o == i)
713 continue;
714
715 if (meshEdges[i].x == meshEdges[o].x || meshEdges[i].y == meshEdges[o].x ||
716 meshEdges[i].x == meshEdges[o].y || meshEdges[i].y == meshEdges[o].y)
717 continue;
718
719 var otherSelectionIndex = FindSelectionIndexFromEdge(in selection, meshEdges[o]);
720 var otherEdgeStart = otherSelectionIndex.x != -1 ? movedVertices[otherSelectionIndex.x] : meshVertices[meshEdges[o].x];
721 var otherEdgeEnd = otherSelectionIndex.y != -1 ? movedVertices[otherSelectionIndex.y] : meshVertices[meshEdges[o].y];
722
723 if (MathUtility.SegmentIntersection(edgeStart, edgeEnd, otherEdgeStart, otherEdgeEnd, ref edgeIntersectionPoint))
724 return true;
725 }
726 }
727
728 return false;
729 }
730
731 static int2 FindSelectionIndexFromEdge(in int[] selection, int2 edge)
732 {
733 var selectionIndex = new int2(-1, -1);
734 for (var m = 0; m < selection.Length; ++m)
735 {
736 if (selection[m] == edge.x)
737 {
738 selectionIndex.x = m;
739 break;
740 }
741
742 if (selection[m] == edge.y)
743 {
744 selectionIndex.y = m;
745 break;
746 }
747 }
748
749 return selectionIndex;
750 }
751
752 static bool IsMovedVertexIntersectingWithOutline(in int[] selection, in Vector2[] movedVertices, in int2[] outlineEdges, in Vector2[] meshVertices)
753 {
754 var edgeIntersectionPoint = Vector2.zero;
755
756 for (var i = 0; i < selection.Length; ++i)
757 {
758 var edgeStart = meshVertices[selection[i]];
759 var edgeEnd = movedVertices[i];
760
761 for (var m = 0; m < outlineEdges.Length; ++m)
762 {
763 if (selection[i] == outlineEdges[m].x || selection[i] == outlineEdges[m].y)
764 continue;
765
766 var otherSelectionIndex = FindSelectionIndexFromEdge(in selection, outlineEdges[m]);
767 var otherEdgeStart = otherSelectionIndex.x != -1 ? movedVertices[otherSelectionIndex.x] : meshVertices[outlineEdges[m].x];
768 var otherEdgeEnd = otherSelectionIndex.y != -1 ? movedVertices[otherSelectionIndex.y] : meshVertices[outlineEdges[m].y];
769
770 if (MathUtility.SegmentIntersection(edgeStart, edgeEnd, otherEdgeStart, otherEdgeEnd, ref edgeIntersectionPoint))
771 return true;
772 }
773 }
774
775 return false;
776 }
777 }
778}