mirror of
https://gitgud.io/AbstractConcept/rimworld-animation-studio.git
synced 2024-08-15 00:43:27 +00:00
Initial commit
This commit is contained in:
commit
3c7cc0c973
8391 changed files with 704313 additions and 0 deletions
|
@ -0,0 +1,400 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.U2D;
|
||||
|
||||
namespace UnityEditor.U2D.SpriteShape
|
||||
{
|
||||
public interface IAngleRangeCache
|
||||
{
|
||||
List<AngleRange> angleRanges { get; }
|
||||
int selectedIndex { get; set; }
|
||||
float previewAngle { get; set; }
|
||||
void RegisterUndo(string name);
|
||||
}
|
||||
|
||||
public class AngleRangeController
|
||||
{
|
||||
public event Action selectionChanged = () => { };
|
||||
public IAngleRangeCache cache { get; set; }
|
||||
public IAngleRangeView view { get; set; }
|
||||
public float angleOffset { get; set; }
|
||||
public float radius { get; set; }
|
||||
public Rect rect { get; set; }
|
||||
public bool snap { get; set; }
|
||||
public Color gradientMin { get; set; }
|
||||
public Color gradientMid { get; set; }
|
||||
public Color gradientMax { get; set; }
|
||||
|
||||
public AngleRange selectedAngleRange
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(cache != null);
|
||||
|
||||
AngleRange angleRange = null;
|
||||
|
||||
if (cache.selectedIndex >= 0 && cache.selectedIndex < cache.angleRanges.Count)
|
||||
return cache.angleRanges[cache.selectedIndex];
|
||||
|
||||
return angleRange;
|
||||
}
|
||||
}
|
||||
|
||||
private AngleRange hoveredAngleRange
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(cache != null);
|
||||
Debug.Assert(view != null);
|
||||
|
||||
AngleRange angleRange = null;
|
||||
|
||||
if (view.hoveredRangeIndex >= 0 && view.hoveredRangeIndex < cache.angleRanges.Count)
|
||||
return cache.angleRanges[view.hoveredRangeIndex];
|
||||
|
||||
return angleRange;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
Debug.Assert(cache != null);
|
||||
|
||||
view.SetupLayout(rect, angleOffset, radius);
|
||||
|
||||
DoAngleRanges();
|
||||
HandleSelectAngleRange();
|
||||
HandleCreateRange();
|
||||
HandlePreviewSelector();
|
||||
HandleRemoveRange();
|
||||
}
|
||||
|
||||
private void DoAngleRanges()
|
||||
{
|
||||
var removeInvalid = false;
|
||||
|
||||
if (view.IsActionTriggering(AngleRangeAction.ModifyRange))
|
||||
cache.RegisterUndo("Modify Range");
|
||||
|
||||
if (view.IsActionFinishing(AngleRangeAction.ModifyRange))
|
||||
removeInvalid = true;
|
||||
|
||||
var index = 0;
|
||||
foreach (var angleRange in cache.angleRanges)
|
||||
{
|
||||
var start = angleRange.start;
|
||||
var end = angleRange.end;
|
||||
var isSelected = selectedAngleRange != null && selectedAngleRange == angleRange;
|
||||
|
||||
if (view.DoAngleRange(index, rect, radius, angleOffset, ref start, ref end, snap, !isSelected, gradientMin, gradientMid, gradientMax))
|
||||
SetRange(angleRange, start, end);
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
if (removeInvalid)
|
||||
RemoveInvalidRanges();
|
||||
}
|
||||
|
||||
public void RemoveInvalidRanges()
|
||||
{
|
||||
var toDelete = new List<AngleRange>();
|
||||
|
||||
foreach (var angleRange in cache.angleRanges)
|
||||
{
|
||||
var start = angleRange.start;
|
||||
var end = angleRange.end;
|
||||
|
||||
if (start >= end)
|
||||
toDelete.Add(angleRange);
|
||||
}
|
||||
|
||||
foreach (var angleRange in toDelete)
|
||||
cache.angleRanges.Remove(angleRange);
|
||||
|
||||
if (toDelete.Count > 0)
|
||||
{
|
||||
SetSelectedIndexFromPreviewAngle();
|
||||
view.Repaint();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSelectAngleRange()
|
||||
{
|
||||
int newSelected;
|
||||
if (view.DoSelectAngleRange(cache.selectedIndex, out newSelected))
|
||||
{
|
||||
cache.RegisterUndo("Select Angle Range");
|
||||
cache.previewAngle = view.GetAngleFromPosition(rect, angleOffset);
|
||||
SelectIndex(newSelected);
|
||||
}
|
||||
|
||||
if (view.IsActionActive(AngleRangeAction.SelectRange))
|
||||
{
|
||||
if (hoveredAngleRange == null)
|
||||
return;
|
||||
|
||||
view.DrawAngleRangeOutline(rect, hoveredAngleRange.start, hoveredAngleRange.end, angleOffset, radius);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCreateRange()
|
||||
{
|
||||
if (!view.IsActionActive(AngleRangeAction.CreateRange))
|
||||
return;
|
||||
|
||||
var angle = view.GetAngleFromPosition(rect, angleOffset);
|
||||
var start = 0f;
|
||||
var end = 0f;
|
||||
var canCreate = GetNewRangeBounds(angle, out start, out end);
|
||||
|
||||
if (canCreate && view.DoCreateRange(rect, radius, angleOffset, start, end))
|
||||
{
|
||||
CreateRangeAtAngle(angle);
|
||||
cache.previewAngle = angle;
|
||||
SetSelectedIndexFromPreviewAngle();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandlePreviewSelector()
|
||||
{
|
||||
if (view.IsActionTriggering(AngleRangeAction.ModifySelector))
|
||||
cache.RegisterUndo("Set Preview Angle");
|
||||
|
||||
float newAngle;
|
||||
if (view.DoSelector(rect, angleOffset, radius, cache.previewAngle, out newAngle))
|
||||
{
|
||||
if (selectedAngleRange == null)
|
||||
newAngle = Mathf.Repeat(newAngle + 180f, 360f) - 180f;
|
||||
|
||||
cache.previewAngle = newAngle;
|
||||
SetSelectedIndexFromPreviewAngle();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSelectedIndexFromPreviewAngle()
|
||||
{
|
||||
var index = SpriteShapeEditorUtility.GetRangeIndexFromAngle(cache.angleRanges, cache.previewAngle);
|
||||
SelectIndex(index);
|
||||
}
|
||||
|
||||
private void SelectIndex(int index)
|
||||
{
|
||||
view.RequestFocusIndex(index);
|
||||
|
||||
if (cache.selectedIndex == index)
|
||||
return;
|
||||
|
||||
cache.selectedIndex = index;
|
||||
selectionChanged();
|
||||
}
|
||||
|
||||
private void ClampPreviewAngle(float start, float end, float prevStart, float prevEnd)
|
||||
{
|
||||
var angle = cache.previewAngle;
|
||||
|
||||
if (prevStart < start)
|
||||
{
|
||||
var a1 = Mathf.Repeat(angle - prevStart, 360f);
|
||||
var a2 = Mathf.Repeat(angle - start, 360f);
|
||||
|
||||
if (a1 < a2)
|
||||
angle = Mathf.Min(start, end);
|
||||
}
|
||||
else if (prevEnd > end)
|
||||
{
|
||||
var a1 = Mathf.Repeat(prevEnd - angle, 360f);
|
||||
var a2 = Mathf.Repeat(end - angle, 360f);
|
||||
|
||||
if (a1 < a2)
|
||||
angle = Mathf.Max(start, end);
|
||||
}
|
||||
|
||||
cache.previewAngle = angle;
|
||||
}
|
||||
|
||||
private void HandleRemoveRange()
|
||||
{
|
||||
if (view.DoRemoveRange())
|
||||
{
|
||||
cache.RegisterUndo("Remove Range");
|
||||
cache.angleRanges.RemoveAt(cache.selectedIndex);
|
||||
SelectIndex(-1);
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateRange()
|
||||
{
|
||||
CreateRangeAtAngle(cache.previewAngle);
|
||||
}
|
||||
|
||||
private void CreateRangeAtAngle(float angle)
|
||||
{
|
||||
var start = 0f;
|
||||
var end = 0f;
|
||||
|
||||
if (GetNewRangeBounds(angle, out start, out end))
|
||||
{
|
||||
cache.RegisterUndo("Create Range");
|
||||
|
||||
var angleRange = new AngleRange();
|
||||
angleRange.start = start;
|
||||
angleRange.end = end;
|
||||
|
||||
cache.angleRanges.Add(angleRange);
|
||||
|
||||
ValidateRange(angleRange);
|
||||
SetSelectedIndexFromPreviewAngle();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRange(AngleRange angleRange, float start, float end)
|
||||
{
|
||||
var prevStart = angleRange.start;
|
||||
var prevEnd = angleRange.end;
|
||||
|
||||
angleRange.start = start;
|
||||
angleRange.end = end;
|
||||
|
||||
ValidateRange(angleRange, prevStart, prevEnd);
|
||||
|
||||
if (angleRange == selectedAngleRange)
|
||||
ClampPreviewAngle(start, end, prevStart, prevEnd);
|
||||
}
|
||||
|
||||
private bool GetNewRangeBounds(float angle, out float emptyRangeStart, out float emptyRangeEnd)
|
||||
{
|
||||
angle = Mathf.Repeat(angle + 180f, 360f) - 180f;
|
||||
|
||||
emptyRangeStart = float.MinValue;
|
||||
emptyRangeEnd = float.MaxValue;
|
||||
|
||||
if (GetAngleRangeAt(angle) != null)
|
||||
return false;
|
||||
|
||||
FindMinMax(out emptyRangeEnd, out emptyRangeStart);
|
||||
|
||||
if (angle < emptyRangeStart)
|
||||
emptyRangeStart -= 360f;
|
||||
|
||||
if (angle > emptyRangeEnd)
|
||||
emptyRangeEnd += 360f;
|
||||
|
||||
foreach (var angleRange in cache.angleRanges)
|
||||
{
|
||||
var start = angleRange.start;
|
||||
var end = angleRange.end;
|
||||
|
||||
if (angle > end)
|
||||
emptyRangeStart = Mathf.Max(emptyRangeStart, end);
|
||||
|
||||
if (angle < start)
|
||||
emptyRangeEnd = Mathf.Min(emptyRangeEnd, start);
|
||||
}
|
||||
|
||||
var rangeLength = emptyRangeEnd - emptyRangeStart;
|
||||
|
||||
if (rangeLength > 90f)
|
||||
{
|
||||
emptyRangeStart = Mathf.Max(angle - 45f, emptyRangeStart);
|
||||
emptyRangeEnd = Mathf.Min(angle + 45f, emptyRangeEnd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private AngleRange GetAngleRangeAt(float angle)
|
||||
{
|
||||
foreach (var angleRange in cache.angleRanges)
|
||||
{
|
||||
var start = angleRange.start;
|
||||
var end = angleRange.end;
|
||||
var range = end - start;
|
||||
|
||||
var angle2 = Mathf.Repeat(angle - start, 360f);
|
||||
|
||||
if (angle2 >= 0f && angle2 <= range)
|
||||
return angleRange;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void FindMinMax(out float min, out float max)
|
||||
{
|
||||
min = float.MaxValue;
|
||||
max = float.MinValue;
|
||||
|
||||
foreach (var angleRange in cache.angleRanges)
|
||||
{
|
||||
min = Mathf.Min(angleRange.start, min);
|
||||
max = Mathf.Max(angleRange.end, max);
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateRange(AngleRange range)
|
||||
{
|
||||
ValidateRange(range, range.start, range.end);
|
||||
}
|
||||
|
||||
private void ValidateRange(AngleRange angleRange, float prevStart, float prevEnd)
|
||||
{
|
||||
var start = angleRange.start;
|
||||
var end = angleRange.end;
|
||||
|
||||
foreach (var otherRange in cache.angleRanges)
|
||||
{
|
||||
var otherStart = otherRange.start;
|
||||
var otherEnd = otherRange.end;
|
||||
|
||||
if (otherRange == angleRange)
|
||||
{
|
||||
if ((start > 180f && end > 180f) || (start < -180f && end < -180f))
|
||||
{
|
||||
start = Mathf.Repeat(start + 180f, 360f) - 180f;
|
||||
end = Mathf.Repeat(end + 180f, 360f) - 180f;
|
||||
}
|
||||
|
||||
otherStart = start + 360f;
|
||||
otherEnd = end - 360f;
|
||||
}
|
||||
|
||||
ValidateRangeStartEnd(ref start, ref end, prevStart, prevEnd, otherStart, otherEnd);
|
||||
}
|
||||
|
||||
angleRange.start = start;
|
||||
angleRange.end = end;
|
||||
}
|
||||
|
||||
private void ValidateRangeStartEnd(ref float start, ref float end, float prevStart, float prevEnd, float otherStart, float otherEnd)
|
||||
{
|
||||
var min = Mathf.Min(start, otherStart);
|
||||
var max = Mathf.Max(end, otherEnd);
|
||||
|
||||
start -= min;
|
||||
end -= min;
|
||||
otherStart -= min;
|
||||
otherEnd -= min;
|
||||
prevStart -= min;
|
||||
prevEnd -= min;
|
||||
|
||||
if (prevEnd != end)
|
||||
end = Mathf.Clamp(end, start, otherStart >= start ? otherStart : 360f);
|
||||
|
||||
start += min - max;
|
||||
end += min - max;
|
||||
otherStart += min - max;
|
||||
otherEnd += min - max;
|
||||
prevStart += min - max;
|
||||
prevEnd += min - max;
|
||||
|
||||
if (prevStart != start)
|
||||
start = Mathf.Clamp(start, otherEnd <= end ? otherEnd : -360f, end);
|
||||
|
||||
start += max;
|
||||
end += max;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue