EditModeMixUtils.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using UnityEngine.Timeline;
  4. namespace UnityEditor.Timeline
  5. {
  6. static class EditModeMixUtils
  7. {
  8. static readonly List<PlacementValidity> k_UnrecoverablePlacements = new List<PlacementValidity>
  9. {
  10. PlacementValidity.InvalidIsWithin,
  11. PlacementValidity.InvalidStartsInBlend,
  12. PlacementValidity.InvalidContainsBlend
  13. };
  14. public static bool CanInsert(IEnumerable<ItemsPerTrack> itemsGroups)
  15. {
  16. foreach (var itemsGroup in itemsGroups)
  17. {
  18. var siblings = ItemsUtils.GetItemsExcept(itemsGroup.targetTrack, itemsGroup.items);
  19. foreach (var item in itemsGroup.items)
  20. {
  21. var placementValidity = GetPlacementValidity(item, siblings);
  22. if (k_UnrecoverablePlacements.Contains(placementValidity))
  23. {
  24. return false;
  25. }
  26. }
  27. }
  28. return true;
  29. }
  30. //Corrects clips durations to fit at insertion point, if needed
  31. public static void PrepareItemsForInsertion(IEnumerable<ItemsPerTrack> itemsGroups)
  32. {
  33. foreach (var itemsGroup in itemsGroups)
  34. {
  35. var siblings = ItemsUtils.GetItemsExcept(itemsGroup.targetTrack, itemsGroup.items);
  36. foreach (var item in itemsGroup.items.OfType<ITrimmable>())
  37. {
  38. var eatenItems = siblings.Where(c => EditModeUtils.IsItemWithinRange(c, item.start, item.end)).ToList();
  39. var intersectedItem = EditModeUtils.GetFirstIntersectedItem(siblings, item.end);
  40. if (intersectedItem != null)
  41. eatenItems.Add(intersectedItem);
  42. var blendableItems = eatenItems.OfType<IBlendable>();
  43. if (blendableItems.Any())
  44. {
  45. var minTime = blendableItems.Min(c => c.end - c.rightBlendDuration);
  46. if (item.end > minTime)
  47. item.SetEnd(minTime, false);
  48. }
  49. }
  50. }
  51. }
  52. public static PlacementValidity GetPlacementValidity(ITimelineItem item, IEnumerable<ITimelineItem> otherItems)
  53. {
  54. if (item.duration <= 0.0)
  55. return PlacementValidity.Valid; //items without any duration can always be placed
  56. var sortedItems = otherItems.Where(i => i.duration > 0.0).OrderBy(c => c.start);
  57. var candidates = new List<ITimelineItem>();
  58. foreach (var sortedItem in sortedItems)
  59. {
  60. if ((DiscreteTime)sortedItem.start >= (DiscreteTime)item.end)
  61. {
  62. // No need to process further
  63. break;
  64. }
  65. if ((DiscreteTime)sortedItem.end <= (DiscreteTime)item.start)
  66. {
  67. // Skip
  68. continue;
  69. }
  70. candidates.Add(sortedItem);
  71. }
  72. var discreteStart = (DiscreteTime)item.start;
  73. var discreteEnd = (DiscreteTime)item.end;
  74. // Note: Order of tests matters
  75. for (int i = 0, n = candidates.Count; i < n; i++)
  76. {
  77. var candidate = candidates[i];
  78. var blendItem = item as IBlendable;
  79. if (blendItem != null && blendItem.supportsBlending)
  80. {
  81. if (EditModeUtils.Contains(candidate.start, candidate.end, item))
  82. return PlacementValidity.InvalidIsWithin;
  83. if (i < n - 1)
  84. {
  85. var nextCandidate = candidates[i + 1];
  86. var discreteNextCandidateStart = (DiscreteTime)nextCandidate.start;
  87. var discreteCandidateEnd = (DiscreteTime)candidate.end;
  88. if (discreteCandidateEnd > discreteNextCandidateStart)
  89. {
  90. if (discreteStart >= discreteNextCandidateStart)
  91. {
  92. // Note: In case the placement is fully within a blend,
  93. // InvalidStartsInBlend MUST have priority
  94. return PlacementValidity.InvalidStartsInBlend;
  95. }
  96. if (discreteEnd > discreteNextCandidateStart && discreteEnd <= discreteCandidateEnd)
  97. return PlacementValidity.InvalidEndsInBlend;
  98. if (discreteStart < discreteNextCandidateStart && discreteEnd > discreteCandidateEnd)
  99. return PlacementValidity.InvalidContainsBlend;
  100. }
  101. }
  102. if (EditModeUtils.Contains(item.start, item.end, candidate))
  103. return PlacementValidity.InvalidContains;
  104. }
  105. else
  106. {
  107. if (EditModeUtils.Overlaps(item, candidate.start, candidate.end)
  108. || EditModeUtils.Overlaps(candidate, item.start, item.end))
  109. return PlacementValidity.InvalidOverlapWithNonBlendableClip;
  110. }
  111. }
  112. return PlacementValidity.Valid;
  113. }
  114. }
  115. }