Initial commit

This commit is contained in:
AbstractConcept 2022-09-13 00:36:34 -05:00
commit 3c7cc0c973
8391 changed files with 704313 additions and 0 deletions

View file

@ -0,0 +1,127 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class Brush
{
private static readonly float kWheelSizeSpeed = 1f;
private static readonly int kBrushHashCode = "Brush".GetHashCode();
private IGUIWrapper m_GUIWrapper;
private float m_DeltaAcc = 0f;
private int m_ControlID = -1;
private SliderData m_SliderData = SliderData.zero;
public event Action<Brush> onMove = (b) => {};
public event Action<Brush> onSize = (b) => {};
public event Action<Brush> onRepaint = (b) => {};
public event Action<Brush> onStrokeBegin = (b) => {};
public event Action<Brush> onStrokeDelta = (b) => {};
public event Action<Brush> onStrokeStep = (b) => {};
public event Action<Brush> onStrokeEnd = (b) => {};
public bool isHot
{
get { return m_GUIWrapper.IsControlHot(m_ControlID); }
}
public bool isActivable
{
get { return m_GUIWrapper.IsControlHot(0) && m_GUIWrapper.IsControlNearest(m_ControlID); }
}
public int controlID
{
get { return m_ControlID; }
}
public float hardness { get; set; }
public float step { get; set; }
public float size { get; set; }
public Vector3 position
{
get { return m_SliderData.position; }
}
public Brush(IGUIWrapper guiWrapper)
{
m_GUIWrapper = guiWrapper;
size = 25f;
step = 20f;
}
public void OnGUI()
{
m_ControlID = m_GUIWrapper.GetControlID(kBrushHashCode, FocusType.Passive);
var eventType = m_GUIWrapper.eventType;
if (!m_GUIWrapper.isAltDown)
m_GUIWrapper.LayoutControl(controlID, 0f);
if (isActivable)
{
m_SliderData.position = m_GUIWrapper.GUIToWorld(m_GUIWrapper.mousePosition);
if (m_GUIWrapper.IsMouseDown(0))
{
m_DeltaAcc = 0f;
onStrokeBegin(this);
onStrokeStep(this);
m_GUIWrapper.SetGuiChanged(true);
}
if (eventType == EventType.MouseMove)
{
onMove(this);
m_GUIWrapper.UseCurrentEvent();
}
if (m_GUIWrapper.isShiftDown && eventType == EventType.ScrollWheel)
{
var sizeDelta = HandleUtility.niceMouseDeltaZoom * kWheelSizeSpeed;
size = Mathf.Max(1f, size + sizeDelta);
onSize(this);
m_GUIWrapper.UseCurrentEvent();
}
}
if (isHot && m_GUIWrapper.IsMouseUp(0))
onStrokeEnd(this);
if (m_GUIWrapper.IsRepainting() && (isHot || isActivable))
onRepaint(this);
Vector3 position;
if (m_GUIWrapper.DoSlider(m_ControlID, m_SliderData, out position))
{
step = Mathf.Max(step, 1f);
var delta = position - m_SliderData.position;
var direction = delta.normalized;
var magnitude = delta.magnitude;
m_SliderData.position -= direction * m_DeltaAcc;
m_DeltaAcc += magnitude;
if (m_DeltaAcc >= step)
{
var stepVector = direction * step;
while (m_DeltaAcc >= step)
{
m_SliderData.position += stepVector;
onMove(this);
onStrokeStep(this);
m_DeltaAcc -= step;
}
}
m_SliderData.position = position;
onStrokeDelta(this);
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 06c115e22e25aad4e9a720594b10fa29
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,230 @@
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal struct SliderData
{
public Vector3 position;
public Vector3 forward;
public Vector3 up;
public Vector3 right;
public static readonly SliderData zero = new SliderData() { position = Vector3.zero, forward = Vector3.forward, up = Vector3.up, right = Vector3.right };
}
internal interface IGUIWrapper
{
Vector2 mousePosition { get; }
int mouseButton { get; }
int clickCount { get; }
bool isShiftDown { get; }
bool isAltDown { get; }
bool isActionKeyDown { get; }
EventType eventType { get; }
string commandName { get; }
bool IsMouseDown(int button);
bool IsMouseUp(int button);
bool IsKeyDown(KeyCode keyCode);
int GetControlID(int hint, FocusType focusType);
void LayoutControl(int controlID, float distance);
bool IsControlNearest(int controlID);
bool IsControlHot(int controlID);
bool IsMultiStepControlHot(int controlID);
void SetControlHot(int controlID);
void SetMultiStepControlHot(int controlID);
bool DoSlider(int id, SliderData sliderData, out Vector3 newPosition);
void UseCurrentEvent();
float DistanceToSegment(Vector3 p1, Vector3 p2);
float DistanceToSegmentClamp(Vector3 p1, Vector3 p2);
float DistanceToCircle(Vector3 center, float radius);
Vector3 GUIToWorld(Vector2 guiPosition);
Vector3 GUIToWorld(Vector2 guiPosition, Vector3 planeNormal, Vector3 planePosition);
void Repaint();
bool IsRepainting();
bool IsEventOutsideWindow();
void SetGuiChanged(bool changed);
float GetHandleSize(Vector3 position);
bool IsViewToolActive();
bool HasCurrentCamera();
}
internal class GUIWrapper : IGUIWrapper
{
private Handles.CapFunction nullCap = (int c, Vector3 p , Quaternion r, float s, EventType ev) => {};
private int m_MultiStepHotControl = 0;
public Vector2 mousePosition
{
get { return Event.current.mousePosition; }
}
public int mouseButton
{
get { return Event.current.button; }
}
public int clickCount
{
get { return Event.current.clickCount; }
}
public bool isShiftDown
{
get { return Event.current.shift; }
}
public bool isAltDown
{
get { return Event.current.alt; }
}
public bool isActionKeyDown
{
get { return EditorGUI.actionKey; }
}
public EventType eventType
{
get { return Event.current.type; }
}
public string commandName
{
get { return Event.current.commandName; }
}
public bool IsMouseDown(int button)
{
return Event.current.type == EventType.MouseDown && Event.current.button == button;
}
public bool IsMouseUp(int button)
{
return Event.current.type == EventType.MouseUp && Event.current.button == button;
}
public bool IsKeyDown(KeyCode keyCode)
{
return Event.current.type == EventType.KeyDown && Event.current.keyCode == keyCode;
}
public int GetControlID(int hint, FocusType focusType)
{
return GUIUtility.GetControlID(hint, focusType);
}
public void LayoutControl(int controlID, float distance)
{
if (Event.current.type == EventType.Layout)
HandleUtility.AddControl(controlID, distance);
}
public bool IsControlNearest(int controlID)
{
return HandleUtility.nearestControl == controlID;
}
public bool IsControlHot(int controlID)
{
return GUIUtility.hotControl == controlID;
}
public bool IsMultiStepControlHot(int controlID)
{
return m_MultiStepHotControl == controlID;
}
public void SetControlHot(int controlID)
{
GUIUtility.hotControl = controlID;
}
public void SetMultiStepControlHot(int controlID)
{
m_MultiStepHotControl = controlID;
}
public bool DoSlider(int id, SliderData sliderData, out Vector3 newPosition)
{
EditorGUI.BeginChangeCheck();
if (HasCurrentCamera())
newPosition = Handles.Slider2D(id, sliderData.position, sliderData.forward, sliderData.right, sliderData.up, 1f, nullCap, Vector2.zero);
else
newPosition = Slider2D.Do(id, sliderData.position, null);
return EditorGUI.EndChangeCheck();
}
public void UseCurrentEvent()
{
Event.current.Use();
}
public float DistanceToSegment(Vector3 p1, Vector3 p2)
{
p1 = HandleUtility.WorldToGUIPoint(p1);
p2 = HandleUtility.WorldToGUIPoint(p2);
return HandleUtility.DistancePointToLineSegment(mousePosition, p1, p2);
}
public float DistanceToSegmentClamp(Vector3 p1, Vector3 p2)
{
p1 = HandleUtility.WorldToGUIPoint(p1);
p2 = HandleUtility.WorldToGUIPoint(p2);
return MathUtility.DistanceToSegmentClamp(mousePosition, p1, p2);
}
public float DistanceToCircle(Vector3 center, float radius)
{
return HandleUtility.DistanceToCircle(center, radius);
}
public Vector3 GUIToWorld(Vector2 guiPosition)
{
return ModuleUtility.GUIToWorld(guiPosition);
}
public Vector3 GUIToWorld(Vector2 guiPosition, Vector3 planeNormal, Vector3 planePosition)
{
return ModuleUtility.GUIToWorld(guiPosition, planeNormal, planePosition);
}
public void Repaint()
{
HandleUtility.Repaint();
}
public bool IsRepainting()
{
return eventType == EventType.Repaint;
}
public void SetGuiChanged(bool changed)
{
GUI.changed = true;
}
public bool IsEventOutsideWindow()
{
return Event.current.type == EventType.Ignore;
}
public float GetHandleSize(Vector3 position)
{
return HandleUtility.GetHandleSize(position);
}
public bool IsViewToolActive()
{
return UnityEditor.Tools.current == Tool.View || isAltDown || mouseButton == 1 || mouseButton == 2;
}
public bool HasCurrentCamera()
{
return Camera.current != null;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 71855e9e46fcdd7408882b24732e4808
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,67 @@
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal enum SkeletonAction
{
None = 0,
Select = 1 << 0,
RotateBone = 1 << 2,
MoveBone = 1 << 3,
FreeMoveBone = 1 << 4,
MoveEndPosition = 1 << 5,
MoveJoint = 1 << 6,
ChangeLength = 1 << 7,
CreateBone = 1 << 8,
SplitBone = 1 << 9,
Remove = 1 << 10,
}
internal enum SkeletonMode
{
Disabled = SkeletonAction.None,
Selection = SkeletonAction.Select,
EditPose = Selection | SkeletonAction.RotateBone | SkeletonAction.MoveBone,
EditJoints = Selection | SkeletonAction.FreeMoveBone | SkeletonAction.MoveEndPosition | SkeletonAction.MoveJoint | SkeletonAction.Remove,
CreateBone = Selection | SkeletonAction.MoveJoint | SkeletonAction.Remove | SkeletonAction.CreateBone,
SplitBone = Selection | SkeletonAction.MoveEndPosition | SkeletonAction.MoveJoint | SkeletonAction.Remove | SkeletonAction.SplitBone,
}
internal interface ISkeletonView
{
int InvalidID { get; set; }
SkeletonMode mode { get; set; }
int defaultControlID { get; set; }
int hoveredBoneID { get; }
int hoveredJointID { get; }
int hoveredBodyID { get; }
int hoveredTailID { get; }
int hotBoneID { get; }
void BeginLayout();
void EndLayout();
bool CanLayout();
Vector3 GetMouseWorldPosition(Vector3 planeNormal, Vector3 planePosition);
void LayoutBone(int id, Vector3 position, Vector3 endPosition, Vector3 forward, Vector3 up, Vector3 right, bool isChainEnd);
bool DoSelectBone(out int id, out bool additive);
bool DoRotateBone(Vector3 pivot, Vector3 normal, out float deltaAngle);
bool DoMoveBone(out Vector3 deltaPosition);
bool DoFreeMoveBone(out Vector3 deltaPosition);
bool DoMoveJoint(out Vector3 deltaPosition);
bool DoMoveEndPosition(out Vector3 endPosition);
bool DoChangeLength(out Vector3 endPosition);
bool DoCreateBoneStart(out Vector3 position);
bool DoCreateBone(out Vector3 position);
bool DoSplitBone(out int id, out Vector3 position);
bool DoRemoveBone();
bool DoCancelMultistepAction(bool force);
bool IsActionActive(SkeletonAction action);
bool IsActionHot(SkeletonAction action);
bool IsActionTriggering(SkeletonAction action);
bool IsActionFinishing(SkeletonAction action);
bool IsRepainting();
void DrawBone(Vector3 position, Vector3 right, Vector3 forward, float length, Color color, bool isChained, bool isSelected, bool isJointHovered, bool isTailHovered, bool isHot);
void DrawBoneParentLink(Vector3 parentPosition, Vector3 position, Vector3 forward, Color color);
void DrawBoneOutline(Vector3 position, Vector3 right, Vector3 forward, float length, Color color, float outlineScale);
void DrawCursors(bool canBeActive);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 87771fd0f1d988d478a8f45923440eb8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,66 @@
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal enum SpriteMeshViewMode
{
EditGeometry,
CreateVertex,
CreateEdge,
SplitEdge
}
internal enum MeshEditorAction
{
None,
CreateVertex,
MoveVertex,
CreateEdge,
SplitEdge,
MoveEdge,
SelectVertex,
SelectEdge,
Remove
}
internal interface ISpriteMeshView
{
SpriteMeshViewMode mode { get; set; }
ISelection<int> selection { get; set; }
int defaultControlID { get; set; }
Rect frame { get; set; }
Vector2 mouseWorldPosition { get; }
int hoveredVertex { get; }
int hoveredEdge { get; }
int closestEdge { get; }
void CancelMode();
void BeginLayout();
void EndLayout();
void LayoutVertex(Vector2 position, int index);
void LayoutEdge(Vector2 startPosition, Vector2 endPosition, int index);
bool DoCreateVertex();
bool DoSelectVertex(out bool additive);
bool DoMoveVertex(out Vector2 delta);
bool DoMoveEdge(out Vector2 delta);
bool DoCreateEdge();
bool DoSplitEdge();
bool DoSelectEdge(out bool additive);
bool DoRemove();
void DrawVertex(Vector2 position);
void DrawVertexHovered(Vector2 position);
void DrawVertexSelected(Vector2 position);
void BeginDrawEdges();
void EndDrawEdges();
void DrawEdge(Vector2 startPosition, Vector2 endPosition);
void DrawEdgeHovered(Vector2 startPosition, Vector2 endPosition);
void DrawEdgeSelected(Vector2 startPosition, Vector2 endPosition);
bool IsActionTriggered(MeshEditorAction action);
bool IsActionActive(MeshEditorAction action);
bool IsActionHot(MeshEditorAction action);
Vector2 WorldToScreen(Vector2 position);
void DoRepaint();
bool CanRepaint();
bool CanLayout();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 015d7144666ec57449ae83559d3e26c6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,70 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class RectSelectionTool<T>
{
private int m_HashCode = "RectSelectionTool".GetHashCode();
private int m_ControlID = -1;
private bool m_Moved = false;
private RectSlider m_RectSlider = new RectSlider();
public int controlID { get { return m_ControlID; } }
public IRectSelector<T> rectSelector { get; set; }
public ICacheUndo cacheUndo { get; set; }
public Action onSelectionStart = () => {};
public Action onSelectionUpdate = () => {};
public Action onSelectionEnd = () => {};
public void OnGUI()
{
Debug.Assert(rectSelector != null);
Debug.Assert(cacheUndo != null);
m_ControlID = GUIUtility.GetControlID(m_HashCode, FocusType.Passive);
Event ev = Event.current;
EventType eventType = ev.GetTypeForControl(m_ControlID);
if (GUIUtility.hotControl == 0 && HandleUtility.nearestControl == m_ControlID &&
rectSelector.selection.Count > 0 && eventType == EventType.MouseDown && ev.button == 0 && !ev.alt)
{
m_Moved = false;
onSelectionStart();
}
if (m_Moved && GUIUtility.hotControl == m_ControlID && eventType == EventType.MouseUp && ev.button == 0)
{
cacheUndo.BeginUndoOperation(TextContent.selection);
rectSelector.selection.EndSelection(true);
onSelectionEnd();
}
EditorGUI.BeginChangeCheck();
rectSelector.rect = m_RectSlider.Do(m_ControlID);
if (EditorGUI.EndChangeCheck())
{
if(!m_Moved)
{
cacheUndo.BeginUndoOperation(TextContent.selection);
if(!ev.shift)
rectSelector.selection.Clear();
m_Moved = true;
}
rectSelector.selection.BeginSelection();
rectSelector.Select();
onSelectionUpdate();
}
if (eventType == EventType.Repaint && GUIUtility.hotControl == m_ControlID)
{
DrawingUtility.DrawRect(rectSelector.rect, Vector3.zero, Quaternion.identity, new Color(0f, 1f, 1f, 1f), 0.05f, 0.8f);
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7b6edb0347e814797aa9c181f8e5918f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,38 @@
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class RectSlider
{
private static readonly int kRectSliderHashCode = "RectSlider".GetHashCode();
private Vector2 m_StartPosition = Vector2.zero;
private Vector2 m_Position = Vector2.zero;
internal Rect Do()
{
return Do(GUIUtility.GetControlID(kRectSliderHashCode, FocusType.Passive));
}
internal Rect Do(int controlID)
{
var eventType = Event.current.GetTypeForControl(controlID);
if (eventType == EventType.MouseDown)
{
m_StartPosition = ModuleUtility.GUIToWorld(Event.current.mousePosition);
m_Position = m_StartPosition;
}
if (eventType == EventType.Layout)
HandleUtility.AddDefaultControl(controlID);
m_Position = Slider2D.Do(controlID, m_Position);
var rect = new Rect();
rect.min = m_StartPosition;
rect.max = m_Position;
return rect;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ea09cf179b192498284b7d89afdbff8a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,644 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
[Serializable]
internal class SkeletonController
{
private static readonly string k_DefaultRootName = "root";
private static readonly string k_DefaultBoneName = "bone";
private static Regex s_Regex = new Regex(@"\w+_\d+$", RegexOptions.IgnoreCase);
private SkeletonCache m_Skeleton;
[SerializeField]
private Vector3 m_CreateBoneStartPosition;
[SerializeField]
private BoneCache m_PrevCreatedBone;
private bool m_Moved = false;
private ISkeletonStyle style
{
get
{
if (styleOverride != null)
return styleOverride;
return SkeletonStyles.Default;
}
}
private SkinningCache skinningCache
{
get { return m_Skeleton.skinningCache; }
}
private BoneCache selectedBone
{
get { return selection.activeElement.ToSpriteSheetIfNeeded(); }
set { selection.activeElement = value.ToCharacterIfNeeded(); }
}
private BoneCache[] selectedBones
{
get { return selection.elements.ToSpriteSheetIfNeeded(); }
set { selection.elements = value.ToCharacterIfNeeded(); }
}
private BoneCache rootBone
{
get { return selection.root.ToSpriteSheetIfNeeded(); }
}
private BoneCache[] rootBones
{
get { return selection.roots.ToSpriteSheetIfNeeded(); }
}
public ISkeletonView view { get; set; }
public ISkeletonStyle styleOverride { get; set; }
public IBoneSelection selection { get; set; }
public bool editBindPose { get; set; }
public SkeletonCache skeleton
{
get { return m_Skeleton; }
set { SetSkeleton(value); }
}
public BoneCache hoveredBone
{
get { return GetBone(view.hoveredBoneID); }
}
public BoneCache hoveredTail
{
get { return GetBone(view.hoveredTailID); }
}
public BoneCache hoveredBody
{
get { return GetBone(view.hoveredBodyID); }
}
public BoneCache hoveredJoint
{
get { return GetBone(view.hoveredJointID); }
}
public BoneCache hotBone
{
get { return GetBone(view.hotBoneID); }
}
private BoneCache GetBone(int instanceID)
{
return BaseObject.InstanceIDToObject(instanceID) as BoneCache;
}
private void SetSkeleton(SkeletonCache newSkeleton)
{
if (skeleton != newSkeleton)
{
m_Skeleton = newSkeleton;
Reset();
}
}
public void Reset()
{
view.DoCancelMultistepAction(true);
}
public void OnGUI()
{
if (skeleton == null)
return;
view.BeginLayout();
if (view.CanLayout())
LayoutBones();
view.EndLayout();
HandleSelectBone();
HandleRotateBone();
HandleMoveBone();
HandleFreeMoveBone();
HandleMoveJoint();
HandleMoveEndPosition();
HandleChangeLength();
HandleCreateBone();
HandleSplitBone();
HandleRemoveBone();
HandleCancelMultiStepAction();
DrawSkeleton();
DrawSplitBonePreview();
DrawCreateBonePreview();
DrawCursors();
}
private void LayoutBones()
{
for (var i = 0; i < skeleton.BoneCount; ++i)
{
var bone = skeleton.GetBone(i);
if (bone.isVisible && bone != hotBone)
view.LayoutBone(bone.GetInstanceID(), bone.position, bone.endPosition, bone.forward, bone.up, bone.right, bone.chainedChild == null);
}
}
private void HandleSelectBone()
{
int instanceID;
bool additive;
if (view.DoSelectBone(out instanceID, out additive))
{
var bone = GetBone(instanceID).ToCharacterIfNeeded();
using (skinningCache.UndoScope(TextContent.boneSelection, true))
{
if (!additive)
{
if (!selection.Contains(bone))
selectedBone = bone;
}
else
selection.Select(bone, !selection.Contains(bone));
skinningCache.events.boneSelectionChanged.Invoke();
}
}
}
private void HandleRotateBone()
{
if (view.IsActionTriggering(SkeletonAction.RotateBone))
m_Moved = false;
var pivot = hoveredBone;
if (view.IsActionHot(SkeletonAction.RotateBone))
pivot = hotBone;
if (pivot == null)
return;
var rootBones = selection.roots.ToSpriteSheetIfNeeded();
pivot = pivot.FindRoot<BoneCache>(rootBones);
if (pivot == null)
return;
float deltaAngle;
if (view.DoRotateBone(pivot.position, pivot.forward, out deltaAngle))
{
if (!m_Moved)
{
skinningCache.BeginUndoOperation(TextContent.rotateBone);
m_Moved = true;
}
m_Skeleton.RotateBones(selectedBones, deltaAngle);
InvokePoseChanged();
}
}
private void HandleMoveBone()
{
if (view.IsActionTriggering(SkeletonAction.MoveBone))
m_Moved = false;
Vector3 deltaPosition;
if (view.DoMoveBone(out deltaPosition))
{
if (!m_Moved)
{
skinningCache.BeginUndoOperation(TextContent.moveBone);
m_Moved = true;
}
m_Skeleton.MoveBones(rootBones, deltaPosition);
InvokePoseChanged();
}
}
private void HandleFreeMoveBone()
{
if (view.IsActionTriggering(SkeletonAction.FreeMoveBone))
m_Moved = false;
Vector3 deltaPosition;
if (view.DoFreeMoveBone(out deltaPosition))
{
if (!m_Moved)
{
skinningCache.BeginUndoOperation(TextContent.freeMoveBone);
m_Moved = true;
}
m_Skeleton.FreeMoveBones(selectedBones, deltaPosition);
InvokePoseChanged();
}
}
private void HandleMoveJoint()
{
if (view.IsActionTriggering(SkeletonAction.MoveJoint))
m_Moved = false;
if (view.IsActionFinishing(SkeletonAction.MoveJoint))
{
if (hoveredTail != null && hoveredTail.chainedChild == null && hotBone.parent == hoveredTail)
hoveredTail.chainedChild = hotBone;
}
Vector3 deltaPosition;
if (view.DoMoveJoint(out deltaPosition))
{
if (!m_Moved)
{
skinningCache.BeginUndoOperation(TextContent.moveJoint);
m_Moved = true;
}
//Snap to parent endPosition
if (hoveredTail != null && hoveredTail.chainedChild == null && hotBone.parent == hoveredTail)
deltaPosition = hoveredTail.endPosition - hotBone.position;
m_Skeleton.MoveJoints(selectedBones, deltaPosition);
InvokePoseChanged();
}
}
private void HandleMoveEndPosition()
{
if (view.IsActionTriggering(SkeletonAction.MoveEndPosition))
m_Moved = false;
if (view.IsActionFinishing(SkeletonAction.MoveEndPosition))
{
if (hoveredJoint != null && hoveredJoint.parent == hotBone)
hotBone.chainedChild = hoveredJoint;
}
Vector3 endPosition;
if (view.DoMoveEndPosition(out endPosition))
{
if (!m_Moved)
{
skinningCache.BeginUndoOperation(TextContent.moveEndPoint);
m_Moved = true;
}
Debug.Assert(hotBone != null);
Debug.Assert(hotBone.chainedChild == null);
if (hoveredJoint != null && hoveredJoint.parent == hotBone)
endPosition = hoveredJoint.position;
m_Skeleton.SetEndPosition(hotBone, endPosition);
InvokePoseChanged();
}
}
private void HandleChangeLength()
{
if (view.IsActionTriggering(SkeletonAction.ChangeLength))
m_Moved = false;
Vector3 endPosition;
if (view.DoChangeLength(out endPosition))
{
if (!m_Moved)
{
skinningCache.BeginUndoOperation(TextContent.boneLength);
m_Moved = true;
}
Debug.Assert(hotBone != null);
var direction = (Vector3)endPosition - hotBone.position;
hotBone.length = Vector3.Dot(direction, hotBone.right);
InvokePoseChanged();
}
}
private void HandleCreateBone()
{
Vector3 position;
if (view.DoCreateBoneStart(out position))
{
m_PrevCreatedBone = null;
if (hoveredTail != null)
{
m_PrevCreatedBone = hoveredTail;
m_CreateBoneStartPosition = hoveredTail.endPosition;
}
else
{
m_CreateBoneStartPosition = position;
}
}
if (view.DoCreateBone(out position))
{
using (skinningCache.UndoScope(TextContent.createBone))
{
var isChained = m_PrevCreatedBone != null;
var parentBone = isChained ? m_PrevCreatedBone : rootBone;
if (isChained)
m_CreateBoneStartPosition = m_PrevCreatedBone.endPosition;
var name = AutoBoneName(parentBone, skeleton.bones);
var bone = m_Skeleton.CreateBone(parentBone, m_CreateBoneStartPosition, position, isChained, name);
m_PrevCreatedBone = bone;
m_CreateBoneStartPosition = bone.endPosition;
InvokeTopologyChanged();
InvokePoseChanged();
}
}
}
private void HandleSplitBone()
{
int instanceID;
Vector3 position;
if (view.DoSplitBone(out instanceID, out position))
{
using (skinningCache.UndoScope(TextContent.splitBone))
{
var boneToSplit = GetBone(instanceID);
Debug.Assert(boneToSplit != null);
var splitLength = Vector3.Dot(hoveredBone.right, position - boneToSplit.position);
var name = AutoBoneName(boneToSplit, skeleton.bones);
m_Skeleton.SplitBone(boneToSplit, splitLength, name);
InvokeTopologyChanged();
InvokePoseChanged();
}
}
}
private void HandleRemoveBone()
{
if (view.DoRemoveBone())
{
using (skinningCache.UndoScope(TextContent.removeBone))
{
m_Skeleton.DestroyBones(selectedBones);
selection.Clear();
skinningCache.events.boneSelectionChanged.Invoke();
InvokeTopologyChanged();
InvokePoseChanged();
}
}
}
private void HandleCancelMultiStepAction()
{
if (view.DoCancelMultistepAction(false))
m_PrevCreatedBone = null;
}
private void DrawSkeleton()
{
if (!view.IsRepainting())
return;
bool isNotOnVisualElement = !skinningCache.IsOnVisualElement();
if (view.IsActionActive(SkeletonAction.CreateBone) || view.IsActionHot(SkeletonAction.CreateBone))
{
if (isNotOnVisualElement)
{
var endPoint = view.GetMouseWorldPosition(Vector3.forward, Vector3.zero);
if (view.IsActionHot(SkeletonAction.CreateBone))
endPoint = m_CreateBoneStartPosition;
if (m_PrevCreatedBone == null && hoveredTail == null)
{
var root = rootBone;
if (root != null)
view.DrawBoneParentLink(root.position, endPoint, Vector3.forward, style.GetParentLinkPreviewColor(skeleton.BoneCount));
}
}
}
for (var i = 0; i < skeleton.BoneCount; ++i)
{
var bone = skeleton.GetBone(i);
if (bone.isVisible == false || bone.parentBone == null || bone.parentBone.chainedChild == bone)
continue;
view.DrawBoneParentLink(bone.parent.position, bone.position, Vector3.forward, style.GetParentLinkColor(bone));
}
for (var i = 0; i < skeleton.BoneCount; ++i)
{
var bone = skeleton.GetBone(i);
if ((view.IsActionActive(SkeletonAction.SplitBone) && hoveredBone == bone && isNotOnVisualElement) || bone.isVisible == false)
continue;
var isSelected = selection.Contains(bone.ToCharacterIfNeeded());
var isHovered = hoveredBody == bone && view.IsActionHot(SkeletonAction.None) && isNotOnVisualElement;
DrawBoneOutline(bone, style.GetOutlineColor(bone, isSelected, isHovered), style.GetOutlineScale(isSelected));
}
for (var i = 0; i < skeleton.BoneCount; ++i)
{
var bone = skeleton.GetBone(i);
if ((view.IsActionActive(SkeletonAction.SplitBone) && hoveredBone == bone && isNotOnVisualElement) || bone.isVisible == false)
continue;
DrawBone(bone, style.GetColor(bone));
}
}
private void DrawBone(BoneCache bone, Color color)
{
var isSelected = selection.Contains(bone.ToCharacterIfNeeded());
var isNotOnVisualElement = !skinningCache.IsOnVisualElement();
var isJointHovered = view.IsActionHot(SkeletonAction.None) && hoveredJoint == bone && isNotOnVisualElement;
var isTailHovered = view.IsActionHot(SkeletonAction.None) && hoveredTail == bone && isNotOnVisualElement;
view.DrawBone(bone.position, bone.right, Vector3.forward, bone.length, color, bone.chainedChild != null, isSelected, isJointHovered, isTailHovered, bone == hotBone);
}
private void DrawBoneOutline(BoneCache bone, Color color, float outlineScale)
{
view.DrawBoneOutline(bone.position, bone.right, Vector3.forward, bone.length, color, outlineScale);
}
private void DrawSplitBonePreview()
{
if (!view.IsRepainting())
return;
if (skinningCache.IsOnVisualElement())
return;
if (view.IsActionActive(SkeletonAction.SplitBone) && hoveredBone != null)
{
var splitLength = Vector3.Dot(hoveredBone.right, view.GetMouseWorldPosition(hoveredBone.forward, hoveredBody.position) - hoveredBone.position);
var position = hoveredBone.position + hoveredBone.right * splitLength;
var length = hoveredBone.length - splitLength;
var isSelected = selection.Contains(hoveredBone.ToCharacterIfNeeded());
{
var color = style.GetOutlineColor(hoveredBone, false, false);
if (color.a > 0f)
view.DrawBoneOutline(hoveredBone.position, hoveredBone.right, Vector3.forward, splitLength, style.GetOutlineColor(hoveredBone, isSelected, true), style.GetOutlineScale(false));
}
{
var color = style.GetPreviewOutlineColor(skeleton.BoneCount);
if (color.a > 0f)
view.DrawBoneOutline(position, hoveredBone.right, Vector3.forward, length, style.GetPreviewOutlineColor(skeleton.BoneCount), style.GetOutlineScale(false));
}
view.DrawBone(hoveredBone.position,
hoveredBone.right,
Vector3.forward,
splitLength,
style.GetColor(hoveredBone),
hoveredBone.chainedChild != null,
false, false, false, false);
view.DrawBone(position,
hoveredBone.right,
Vector3.forward,
length,
style.GetPreviewColor(skeleton.BoneCount),
hoveredBone.chainedChild != null,
false, false, false, false);
}
}
private void DrawCreateBonePreview()
{
if (!view.IsRepainting())
return;
if (skinningCache.IsOnVisualElement())
return;
var color = style.GetPreviewColor(skeleton.BoneCount);
var outlineColor = style.GetPreviewOutlineColor(skeleton.BoneCount);
var startPosition = m_CreateBoneStartPosition;
var mousePosition = view.GetMouseWorldPosition(Vector3.forward, Vector3.zero);
if (view.IsActionActive(SkeletonAction.CreateBone))
{
startPosition = mousePosition;
if (hoveredTail != null)
startPosition = hoveredTail.endPosition;
if (outlineColor.a > 0f)
view.DrawBoneOutline(startPosition, Vector3.right, Vector3.forward, 0f, outlineColor, style.GetOutlineScale(false));
view.DrawBone(startPosition, Vector3.right, Vector3.forward, 0f, color, false, false, false, false, false);
}
if (view.IsActionHot(SkeletonAction.CreateBone))
{
var direction = (mousePosition - startPosition);
if (outlineColor.a > 0f)
view.DrawBoneOutline(startPosition, direction.normalized, Vector3.forward, direction.magnitude, outlineColor, style.GetOutlineScale(false));
view.DrawBone(startPosition, direction.normalized, Vector3.forward, direction.magnitude, color, false, false, false, false, false);
}
}
private void DrawCursors()
{
if (!view.IsRepainting())
return;
view.DrawCursors(!skinningCache.IsOnVisualElement());
}
public static string AutoBoneName(BoneCache parent, IEnumerable<BoneCache> bones)
{
string parentName = "root";
string inheritedName;
int counter;
if (parent != null)
parentName = parent.name;
DissectBoneName(parentName, out inheritedName, out counter);
int nameCounter = FindBiggestNameCounter(bones);
if (inheritedName == k_DefaultRootName)
inheritedName = k_DefaultBoneName;
return String.Format("{0}_{1}", inheritedName, ++nameCounter);
}
private static int FindBiggestNameCounter(IEnumerable<BoneCache> bones)
{
int autoNameCounter = 0;
string inheritedName;
int counter;
foreach (var bone in bones)
{
DissectBoneName(bone.name, out inheritedName, out counter);
if (counter > autoNameCounter)
autoNameCounter = counter;
}
return autoNameCounter;
}
private static void DissectBoneName(string boneName, out string inheritedName, out int counter)
{
if (IsBoneNameMatchAutoFormat(boneName))
{
var tokens = boneName.Split('_');
var lastTokenIndex = tokens.Length - 1;
var tokensWithoutLast = new string[lastTokenIndex];
Array.Copy(tokens, tokensWithoutLast, lastTokenIndex);
inheritedName = string.Join("_", tokensWithoutLast);
counter = int.Parse(tokens[lastTokenIndex]);
}
else
{
inheritedName = boneName;
counter = -1;
}
}
private static bool IsBoneNameMatchAutoFormat(string boneName)
{
return s_Regex.IsMatch(boneName);
}
private void InvokeTopologyChanged()
{
skinningCache.events.skeletonTopologyChanged.Invoke(skeleton);
}
private void InvokePoseChanged()
{
skeleton.SetPosePreview();
if (editBindPose)
{
skeleton.SetDefaultPose();
skinningCache.events.skeletonBindPoseChanged.Invoke(skeleton);
}
else
skinningCache.events.skeletonPreviewPoseChanged.Invoke(skeleton);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ea4cc92a263807f4985d77508d2bb536
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,598 @@
using UnityEngine;
using System;
namespace UnityEditor.U2D.Animation
{
internal class SkeletonView : ISkeletonView
{
private const float kPickingRadius = 5f;
internal const string kDeleteCommandName = "Delete";
internal const string kSoftDeleteCommandName = "SoftDelete";
private static readonly int kBodyHashCode = "Body".GetHashCode();
private static readonly int kJointHashCode = "Joint".GetHashCode();
private static readonly int kTailHashCode = "Tail".GetHashCode();
private static readonly int kCreateBoneHashCode = "CreateBone".GetHashCode();
public int InvalidID { get; set; }
public SkeletonMode mode { get; set; }
public int defaultControlID { get; set; }
public int hoveredBoneID { get { return m_HoveredBoneID; } }
public int hoveredJointID { get { return m_HoveredJointID; } }
public int hoveredBodyID { get { return m_HoveredBodyID; } }
public int hoveredTailID { get { return m_HoveredTailID; } }
public int hotBoneID { get { return m_HotBoneID; } }
private IGUIWrapper m_GUIWrapper;
private int m_RotateControlID = -1;
private int m_MoveControlID = -1;
private int m_FreeMoveControlID = -1;
private int m_MoveJointControlID = -1;
private int m_MoveEndPositionControlID = -1;
private int m_ChangeLengthControlID = -1;
private int m_CreateBoneControlID = -1;
private int m_HoveredBoneID = 0;
private int m_PrevHoveredBoneID = 0;
private int m_HoveredBodyID = 0;
private int m_HoveredJointID = 0;
private int m_HoveredTailID = 0;
private int m_HotBoneID = 0;
private int m_HoveredBodyControlID = -1;
private int m_HoveredJointControlID = -1;
private int m_HoveredTailControlID = -1;
private float m_NearestDistance;
private float m_NearestBodyDistance;
private float m_NearestJointDistance;
private float m_NearestTailDistance;
private int m_NearestBodyId = 0;
private int m_NearestJointId = 0;
private int m_NearestTailId = 0;
private SliderData m_HoveredSliderData = SliderData.zero;
private SliderData m_HotSliderData = SliderData.zero;
public SkeletonView(IGUIWrapper gw)
{
m_GUIWrapper = gw;
}
public void BeginLayout()
{
m_HoveredBodyControlID = m_GUIWrapper.GetControlID(kBodyHashCode, FocusType.Passive);
m_HoveredJointControlID = m_GUIWrapper.GetControlID(kJointHashCode, FocusType.Passive);
m_HoveredTailControlID = m_GUIWrapper.GetControlID(kTailHashCode, FocusType.Passive);
m_CreateBoneControlID = m_GUIWrapper.GetControlID(kCreateBoneHashCode, FocusType.Passive);
if (m_GUIWrapper.eventType == EventType.Layout)
{
m_PrevHoveredBoneID = m_HoveredBoneID;
m_NearestDistance = float.MaxValue;
m_NearestBodyDistance = float.MaxValue;
m_NearestJointDistance = float.MaxValue;
m_NearestTailDistance = float.MaxValue;
m_NearestBodyId = InvalidID;
m_NearestJointId = InvalidID;
m_NearestTailId = InvalidID;
m_HoveredBoneID = InvalidID;
m_HoveredBodyID = InvalidID;
m_HoveredJointID = InvalidID;
m_HoveredTailID = InvalidID;
m_HoveredSliderData = SliderData.zero;
if (m_GUIWrapper.IsControlHot(0))
{
m_RotateControlID = -1;
m_MoveControlID = -1;
m_FreeMoveControlID = -1;
m_MoveJointControlID = -1;
m_MoveEndPositionControlID = -1;
m_ChangeLengthControlID = -1;
m_HotBoneID = InvalidID;
}
}
}
public void EndLayout()
{
m_GUIWrapper.LayoutControl(m_HoveredBodyControlID, m_NearestBodyDistance * 0.25f);
m_GUIWrapper.LayoutControl(m_HoveredJointControlID, m_NearestJointDistance);
m_GUIWrapper.LayoutControl(m_HoveredTailControlID, m_NearestTailDistance);
if (m_GUIWrapper.IsControlNearest(m_HoveredBodyControlID))
{
m_HoveredBoneID = m_NearestBodyId;
m_HoveredBodyID = m_NearestBodyId;
}
if (m_GUIWrapper.IsControlNearest(m_HoveredJointControlID))
{
m_HoveredBoneID = m_NearestJointId;
m_HoveredJointID = m_NearestJointId;
}
if (m_GUIWrapper.IsControlNearest(m_HoveredTailControlID))
{
m_HoveredBoneID = m_NearestTailId;
m_HoveredTailID = m_NearestTailId;
}
if ((m_GUIWrapper.eventType == EventType.Layout && m_PrevHoveredBoneID != m_HoveredBoneID) || m_GUIWrapper.eventType == EventType.MouseMove)
m_GUIWrapper.Repaint();
}
public bool CanLayout()
{
return m_GUIWrapper.eventType == EventType.Layout;
}
public void LayoutBone(int id, Vector3 position, Vector3 endPosition, Vector3 forward, Vector3 up, Vector3 right, bool isChainEnd)
{
if (mode == SkeletonMode.Disabled)
return;
var sliderData = new SliderData()
{
position = GetMouseWorldPosition(forward, position),
forward = forward,
up = up,
right = right
};
{
var distance = m_GUIWrapper.DistanceToSegmentClamp(position, endPosition);
if (distance <= m_NearestDistance)
{
m_NearestDistance = distance;
m_NearestBodyDistance = distance;
m_NearestBodyId = id;
m_HoveredSliderData = sliderData;
}
}
{
var distance = m_GUIWrapper.DistanceToCircle(position, GetBoneRadiusForPicking(position) * 2f);
if (distance <= m_NearestDistance)
{
m_NearestDistance = distance;
m_NearestJointDistance = distance;
m_NearestJointId = id;
m_HoveredSliderData = sliderData;
}
}
if (isChainEnd &&
(IsCapable(SkeletonAction.ChangeLength) ||
IsCapable(SkeletonAction.MoveEndPosition) ||
IsCapable(SkeletonAction.CreateBone)))
{
var distance = m_GUIWrapper.DistanceToCircle(endPosition, GetBoneRadiusForPicking(endPosition));
if (distance <= m_NearestDistance)
{
m_NearestDistance = distance;
m_NearestTailDistance = distance;
m_NearestTailId = id;
m_HoveredSliderData = sliderData;
}
}
}
public Vector3 GetMouseWorldPosition(Vector3 planeNormal, Vector3 planePosition)
{
return m_GUIWrapper.GUIToWorld(m_GUIWrapper.mousePosition, planeNormal, planePosition);
}
private float GetBoneRadiusForPicking(Vector3 position)
{
if (m_GUIWrapper.HasCurrentCamera())
return 0.1f * m_GUIWrapper.GetHandleSize(position);
return kPickingRadius;
}
public bool DoSelectBone(out int id, out bool additive)
{
id = 0;
additive = false;
if (IsActionTriggering(SkeletonAction.Select))
{
id = m_HoveredBoneID;
additive = m_GUIWrapper.isActionKeyDown;
if (mode == SkeletonMode.Selection)
{
m_GUIWrapper.UseCurrentEvent();
m_GUIWrapper.SetGuiChanged(true);
}
return true;
}
return false;
}
public bool DoRotateBone(Vector3 pivot, Vector3 normal, out float deltaAngle)
{
deltaAngle = 0f;
Vector3 oldPosition = m_HotSliderData.position;
Vector3 newPosition;
if (DoSliderAction(SkeletonAction.RotateBone, m_HoveredBodyControlID, ref m_RotateControlID, out newPosition))
{
deltaAngle = Vector3.SignedAngle(oldPosition - pivot, (Vector3)newPosition - pivot, normal);
return true;
}
return false;
}
public bool DoMoveBone(out Vector3 deltaPosition)
{
deltaPosition = Vector3.zero;
Vector3 oldPosition = m_HotSliderData.position;
Vector3 newPosition;
if (DoSliderAction(SkeletonAction.MoveBone, m_HoveredJointControlID, ref m_MoveControlID, out newPosition))
{
deltaPosition = newPosition - oldPosition;
return true;
}
return false;
}
public bool DoFreeMoveBone(out Vector3 deltaPosition)
{
deltaPosition = Vector3.zero;
Vector3 oldPosition = m_HotSliderData.position;
Vector3 newPosition;
if (DoSliderAction(SkeletonAction.FreeMoveBone, m_HoveredBodyControlID, ref m_FreeMoveControlID, out newPosition))
{
deltaPosition = newPosition - oldPosition;
return true;
}
return false;
}
public bool DoMoveJoint(out Vector3 deltaPosition)
{
deltaPosition = Vector3.zero;
Vector3 oldPosition = m_HotSliderData.position;
Vector3 newPosition;
if (DoSliderAction(SkeletonAction.MoveJoint, m_HoveredJointControlID, ref m_MoveJointControlID, out newPosition))
{
deltaPosition = newPosition - oldPosition;
return true;
}
return false;
}
public bool DoMoveEndPosition(out Vector3 endPosition)
{
return DoSliderAction(SkeletonAction.MoveEndPosition, m_HoveredTailControlID, ref m_MoveEndPositionControlID, out endPosition);
}
public bool DoChangeLength(out Vector3 endPosition)
{
return DoSliderAction(SkeletonAction.ChangeLength, m_HoveredTailControlID, ref m_ChangeLengthControlID, out endPosition);
}
private bool DoSliderAction(SkeletonAction action, int controlID, ref int actionControlID, out Vector3 newPosition)
{
newPosition = m_HoveredSliderData.position;
if (IsActionTriggering(action))
{
actionControlID = controlID;
m_HotSliderData = m_HoveredSliderData;
m_HotBoneID = hoveredBoneID;
}
if (m_GUIWrapper.DoSlider(actionControlID, m_HotSliderData, out newPosition))
{
m_HotSliderData.position = newPosition;
return true;
}
return false;
}
public bool DoCreateBoneStart(out Vector3 position)
{
position = GetMouseWorldPosition(m_HoveredSliderData.forward, m_HoveredSliderData.position);
if (CanCreateBone())
m_GUIWrapper.LayoutControl(m_CreateBoneControlID, 0f);
if (IsActionActive(SkeletonAction.CreateBone))
ConsumeMouseMoveEvents();
if (IsActionTriggering(SkeletonAction.CreateBone))
{
m_HotBoneID = hoveredBoneID;
m_GUIWrapper.SetMultiStepControlHot(m_CreateBoneControlID);
m_GUIWrapper.UseCurrentEvent();
return true;
}
return false;
}
public bool CanCreateBone()
{
return mode == SkeletonMode.CreateBone && (m_GUIWrapper.IsControlNearest(defaultControlID) || m_GUIWrapper.IsControlNearest(m_HoveredTailControlID));
}
public bool DoCreateBone(out Vector3 position)
{
position = GetMouseWorldPosition(m_HoveredSliderData.forward, m_HoveredSliderData.position);
if (IsActionHot(SkeletonAction.CreateBone))
ConsumeMouseMoveEvents();
if (IsActionFinishing(SkeletonAction.CreateBone))
{
m_GUIWrapper.UseCurrentEvent();
m_GUIWrapper.SetGuiChanged(true);
return true;
}
return false;
}
public bool DoSplitBone(out int id, out Vector3 position)
{
id = m_HoveredBodyID;
position = GetMouseWorldPosition(m_HoveredSliderData.forward, m_HoveredSliderData.position);
if (IsActionActive(SkeletonAction.SplitBone))
ConsumeMouseMoveEvents();
if (IsActionTriggering(SkeletonAction.SplitBone))
{
m_GUIWrapper.UseCurrentEvent();
m_GUIWrapper.SetGuiChanged(true);
return true;
}
return false;
}
public bool DoRemoveBone()
{
if (IsActionTriggering(SkeletonAction.Remove))
{
m_GUIWrapper.UseCurrentEvent();
m_GUIWrapper.SetGuiChanged(true);
return true;
}
return false;
}
public bool DoCancelMultistepAction(bool force)
{
if (force)
{
m_GUIWrapper.SetMultiStepControlHot(0);
return true;
}
if ((!m_GUIWrapper.IsMultiStepControlHot(0) && (m_GUIWrapper.IsMouseDown(1) || m_GUIWrapper.IsKeyDown(KeyCode.Escape))))
{
m_GUIWrapper.SetMultiStepControlHot(0);
m_GUIWrapper.UseCurrentEvent();
return true;
}
return false;
}
public bool IsActionActive(SkeletonAction action)
{
if (m_GUIWrapper.isAltDown || !m_GUIWrapper.IsControlHot(0) || !m_GUIWrapper.IsMultiStepControlHot(0))
return false;
if (action == SkeletonAction.None)
return m_GUIWrapper.IsControlNearest(defaultControlID);
if (!IsCapable(action))
return false;
if (action == SkeletonAction.RotateBone)
return m_GUIWrapper.IsControlNearest(m_HoveredBodyControlID);
if (action == SkeletonAction.ChangeLength)
return m_GUIWrapper.IsControlNearest(m_HoveredTailControlID) && !m_GUIWrapper.isShiftDown;
if (action == SkeletonAction.MoveJoint)
return m_GUIWrapper.IsControlNearest(m_HoveredJointControlID);
if (action == SkeletonAction.MoveEndPosition)
return m_GUIWrapper.IsControlNearest(m_HoveredTailControlID) && !m_GUIWrapper.isShiftDown;
if (action == SkeletonAction.FreeMoveBone)
return m_GUIWrapper.IsControlNearest(m_HoveredBodyControlID);
if (action == SkeletonAction.MoveBone)
return m_GUIWrapper.IsControlNearest(m_HoveredJointControlID);
bool canCreateBone = IsCapable(SkeletonAction.CreateBone) && m_GUIWrapper.IsControlNearest(m_CreateBoneControlID);
bool canSplitBone = IsCapable(SkeletonAction.SplitBone) && m_GUIWrapper.IsControlNearest(m_HoveredBodyControlID);
if (action == SkeletonAction.CreateBone)
return canCreateBone;
if (action == SkeletonAction.SplitBone)
return canSplitBone;
if (action == SkeletonAction.Select)
return (m_GUIWrapper.IsControlNearest(m_HoveredBodyControlID) && !canSplitBone) ||
m_GUIWrapper.IsControlNearest(m_HoveredJointControlID) ||
(m_GUIWrapper.IsControlNearest(m_HoveredTailControlID) && !canCreateBone);
if (action == SkeletonAction.Remove)
return true;
return false;
}
public bool IsActionHot(SkeletonAction action)
{
if (action == SkeletonAction.None)
return m_GUIWrapper.IsControlHot(0) && m_GUIWrapper.IsMultiStepControlHot(0);
if (action == SkeletonAction.RotateBone)
return m_GUIWrapper.IsControlHot(m_RotateControlID);
if (action == SkeletonAction.MoveBone)
return m_GUIWrapper.IsControlHot(m_MoveControlID);
if (action == SkeletonAction.FreeMoveBone)
return m_GUIWrapper.IsControlHot(m_FreeMoveControlID);
if (action == SkeletonAction.MoveJoint)
return m_GUIWrapper.IsControlHot(m_MoveJointControlID);
if (action == SkeletonAction.MoveEndPosition)
return m_GUIWrapper.IsControlHot(m_MoveEndPositionControlID);
if (action == SkeletonAction.ChangeLength)
return m_GUIWrapper.IsControlHot(m_ChangeLengthControlID);
if (action == SkeletonAction.CreateBone)
return m_GUIWrapper.IsMultiStepControlHot(m_CreateBoneControlID) && !m_GUIWrapper.isAltDown;
return false;
}
public bool IsActionTriggering(SkeletonAction action)
{
if (!IsActionActive(action))
return false;
if (action == SkeletonAction.Remove)
{
if ((m_GUIWrapper.eventType == EventType.ValidateCommand || m_GUIWrapper.eventType == EventType.ExecuteCommand)
&& (m_GUIWrapper.commandName == kSoftDeleteCommandName || m_GUIWrapper.commandName == kDeleteCommandName))
{
if (m_GUIWrapper.eventType == EventType.ExecuteCommand)
return true;
m_GUIWrapper.UseCurrentEvent();
}
return false;
}
return m_GUIWrapper.IsMouseDown(0);
}
public bool IsActionFinishing(SkeletonAction action)
{
if (!IsActionHot(action) || !IsCapable(action))
return false;
if (m_GUIWrapper.IsEventOutsideWindow())
return true;
if (action == SkeletonAction.CreateBone)
return m_GUIWrapper.IsMouseDown(0);
return m_GUIWrapper.IsMouseUp(0);
}
public bool IsRepainting()
{
return m_GUIWrapper.IsRepainting();
}
public void DrawBone(Vector3 position, Vector3 right, Vector3 forward, float length, Color color, bool isChained, bool isSelected, bool isJointHovered, bool isTailHovered, bool isHot)
{
var endPosition = position + right * length;
var rotation = Quaternion.LookRotation(forward, Vector3.Cross(right, forward));
var boneBodyColor = color;
var boneJointColor = new Color(0f, 0f, 0f, 0.75f * color.a);
var tailColor = new Color(0f, 0f, 0f, 0.75f * color.a);
var hoveredColor = Handles.preselectionColor;
var selectedColor = Handles.selectedColor;
var drawRectCap = false;
if (isJointHovered)
boneJointColor = hoveredColor;
if (isHot && (IsActionHot(SkeletonAction.MoveBone) || IsActionHot(SkeletonAction.MoveJoint)))
boneJointColor = selectedColor;
if (mode == SkeletonMode.EditPose || mode == SkeletonMode.CreateBone)
{
if (isJointHovered || isSelected)
drawRectCap = true;
}
else if (mode == SkeletonMode.EditJoints || mode == SkeletonMode.SplitBone)
{
rotation = Quaternion.identity;
drawRectCap = true;
}
if (drawRectCap)
Handles.RectangleHandleCap(0, position, rotation, BoneDrawingUtility.GetBoneRadius(position), EventType.Repaint);
BoneDrawingUtility.DrawBone(position, endPosition, forward, boneBodyColor);
BoneDrawingUtility.DrawBoneNode(position, forward, boneJointColor);
if (!isChained &&
(IsCapable(SkeletonAction.ChangeLength) ||
IsCapable(SkeletonAction.MoveEndPosition)))
{
if (isTailHovered)
tailColor = hoveredColor;
if (isHot && (IsActionHot(SkeletonAction.ChangeLength) || IsActionHot(SkeletonAction.MoveEndPosition)))
tailColor = selectedColor;
BoneDrawingUtility.DrawBoneNode(endPosition, forward, tailColor);
}
}
public void DrawBoneParentLink(Vector3 parentPosition, Vector3 position, Vector3 forward, Color color)
{
BoneDrawingUtility.DrawBone(position, parentPosition, forward, color);
}
public void DrawBoneOutline(Vector3 position, Vector3 right, Vector3 forward, float length, Color color, float outlineScale)
{
BoneDrawingUtility.DrawBoneOutline(position, position + right * length, forward, color, outlineScale);
}
public void DrawCursors(bool canBeActive)
{
var mouseScreenRect = new Rect(m_GUIWrapper.mousePosition.x - 100f, m_GUIWrapper.mousePosition.y - 100f, 200f, 200f);
var isRotateHot = IsActionHot(SkeletonAction.RotateBone);
if ((canBeActive && IsActionActive(SkeletonAction.RotateBone)) || isRotateHot)
EditorGUIUtility.AddCursorRect(mouseScreenRect, MouseCursor.RotateArrow);
if ((canBeActive && IsActionActive(SkeletonAction.MoveBone)) || IsActionHot(SkeletonAction.MoveBone) ||
(canBeActive && IsActionActive(SkeletonAction.FreeMoveBone)) || IsActionHot(SkeletonAction.FreeMoveBone) ||
(canBeActive && IsActionActive(SkeletonAction.MoveJoint)) || IsActionHot(SkeletonAction.MoveJoint) ||
(canBeActive && IsActionActive(SkeletonAction.MoveEndPosition)) || IsActionHot(SkeletonAction.MoveEndPosition))
EditorGUIUtility.AddCursorRect(mouseScreenRect, MouseCursor.MoveArrow);
}
private void ConsumeMouseMoveEvents()
{
if (m_GUIWrapper.eventType == EventType.MouseMove || (m_GUIWrapper.eventType == EventType.MouseDrag && m_GUIWrapper.mouseButton == 0))
m_GUIWrapper.UseCurrentEvent();
}
private bool IsCapable(SkeletonAction action)
{
return ((int)mode & (int)action) != 0;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 32b6c1f19cdc32d45aff3ce5c06f3ac3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,78 @@
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class Slider2D
{
private static Vector2 s_CurrentMousePosition;
private static Vector2 s_DragStartScreenPosition;
private static Vector2 s_DragScreenOffset;
private static double s_Time;
public static Vector2 Do(int controlID, Vector2 position, Handles.CapFunction drawCapFunction = null)
{
EventType type = Event.current.GetTypeForControl(controlID);
switch (type)
{
case EventType.MouseDown:
if (Event.current.button == 0 && HandleUtility.nearestControl == controlID && !Event.current.alt)
{
s_Time = EditorApplication.timeSinceStartup;
GUIUtility.keyboardControl = controlID;
GUIUtility.hotControl = controlID;
s_CurrentMousePosition = Event.current.mousePosition;
s_DragStartScreenPosition = Event.current.mousePosition;
Vector2 b = HandleUtility.WorldToGUIPoint(position);
s_DragScreenOffset = s_CurrentMousePosition - b;
Event.current.Use();
}
break;
case EventType.MouseUp:
if (GUIUtility.hotControl == controlID && (Event.current.button == 0 || Event.current.button == 2))
{
GUIUtility.hotControl = 0;
Event.current.Use();
}
break;
case EventType.MouseDrag:
if (GUIUtility.hotControl == controlID)
{
s_CurrentMousePosition = Event.current.mousePosition;
float screenDisplacement = (s_CurrentMousePosition - s_DragStartScreenPosition).magnitude;
Vector2 center = position;
Vector2 screenPosition = s_CurrentMousePosition - s_DragScreenOffset;
position = Handles.inverseMatrix.MultiplyPoint(screenPosition);
float displacement = (center - position).magnitude;
if (!Mathf.Approximately(displacement, 0f) && (EditorApplication.timeSinceStartup - s_Time > 0.15 || screenDisplacement >= 10f))
GUI.changed = true;
Event.current.Use();
}
break;
case EventType.KeyDown:
if (GUIUtility.hotControl == controlID && Event.current.keyCode == KeyCode.Escape)
{
position = Handles.inverseMatrix.MultiplyPoint(s_DragStartScreenPosition - s_DragScreenOffset);
GUIUtility.hotControl = 0;
GUI.changed = true;
Event.current.Use();
}
break;
case EventType.Layout:
if (drawCapFunction != null)
drawCapFunction(controlID, position, Quaternion.identity, 1f, EventType.Layout);
break;
case EventType.Repaint:
if (drawCapFunction != null)
drawCapFunction(controlID, position, Quaternion.identity, 1f, EventType.Repaint);
break;
}
return position;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aaae1a0ac32489e4db7ca7c10f984ade
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,696 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class SpriteMeshController
{
private const float kSnapDistance = 10f;
private struct EdgeIntersectionResult
{
public int startVertexIndex;
public int endVertexIndex;
public int intersectEdgeIndex;
public Vector2 endPosition;
}
private SpriteMeshDataController m_SpriteMeshDataController = new SpriteMeshDataController();
private EdgeIntersectionResult m_EdgeIntersectionResult;
public ISpriteMeshView spriteMeshView { get; set; }
public ISpriteMeshData spriteMeshData
{
get { return m_SpriteMeshData; }
set { m_SpriteMeshData = value; }
}
public ISelection<int> selection { get; set; }
public ICacheUndo cacheUndo { get; set; }
public ITriangulator triangulator { get; set; }
public bool disable { get; set; }
public Rect frame { get; set; }
private ISpriteMeshData m_SpriteMeshData;
private bool m_Moved = false;
public void OnGUI()
{
m_SpriteMeshDataController.spriteMeshData = m_SpriteMeshData;
Debug.Assert(spriteMeshView != null);
Debug.Assert(m_SpriteMeshData != null);
Debug.Assert(selection != null);
Debug.Assert(cacheUndo != null);
spriteMeshView.selection = selection;
spriteMeshView.frame = frame;
EditorGUI.BeginDisabledGroup(disable);
spriteMeshView.BeginLayout();
if(spriteMeshView.CanLayout())
{
LayoutVertices();
LayoutEdges();
}
spriteMeshView.EndLayout();
if(spriteMeshView.CanRepaint())
{
DrawEdges();
if(GUI.enabled)
{
PreviewCreateVertex();
PreviewCreateEdge();
PreviewSplitEdge();
}
DrawVertices();
}
HandleSplitEdge();
HandleCreateEdge();
HandleCreateVertex();
EditorGUI.EndDisabledGroup();
HandleSelectVertex();
EditorGUI.BeginDisabledGroup(disable);
HandleMoveVertex();
EditorGUI.EndDisabledGroup();
HandleSelectEdge();
EditorGUI.BeginDisabledGroup(disable);
HandleMoveEdge();
HandleRemoveEdge();
HandleRemoveVertices();
spriteMeshView.DoRepaint();
EditorGUI.EndDisabledGroup();
}
private void LayoutVertices()
{
for (int i = 0; i < m_SpriteMeshData.vertexCount; i++)
{
Vector2 position = m_SpriteMeshData.GetPosition(i);
spriteMeshView.LayoutVertex(position, i);
}
}
private void LayoutEdges()
{
for (int i = 0; i < m_SpriteMeshData.edges.Count; i++)
{
Edge edge = m_SpriteMeshData.edges[i];
Vector2 startPosition = m_SpriteMeshData.GetPosition(edge.index1);
Vector2 endPosition = m_SpriteMeshData.GetPosition(edge.index2);
spriteMeshView.LayoutEdge(startPosition, endPosition, i);
}
}
private void DrawEdges()
{
UpdateEdgeInstersection();
spriteMeshView.BeginDrawEdges();
for (int i = 0; i < m_SpriteMeshData.edges.Count; ++i)
{
if (SkipDrawEdge(i))
continue;
Edge edge = m_SpriteMeshData.edges[i];
Vector2 startPosition = m_SpriteMeshData.GetPosition(edge.index1);
Vector2 endPosition = m_SpriteMeshData.GetPosition(edge.index2);
if (selection.Contains(edge.index1) && selection.Contains(edge.index2))
spriteMeshView.DrawEdgeSelected(startPosition, endPosition);
else
spriteMeshView.DrawEdge(startPosition, endPosition);
}
if (spriteMeshView.IsActionActive(MeshEditorAction.SelectEdge))
{
Edge hoveredEdge = m_SpriteMeshData.edges[spriteMeshView.hoveredEdge];
Vector2 startPosition = m_SpriteMeshData.GetPosition(hoveredEdge.index1);
Vector2 endPosition = m_SpriteMeshData.GetPosition(hoveredEdge.index2);
spriteMeshView.DrawEdgeHovered(startPosition, endPosition);
}
spriteMeshView.EndDrawEdges();
}
private bool SkipDrawEdge(int edgeIndex)
{
if(GUI.enabled == false)
return false;
return edgeIndex == -1 ||
spriteMeshView.hoveredEdge == edgeIndex && spriteMeshView.IsActionActive(MeshEditorAction.SelectEdge) ||
spriteMeshView.hoveredEdge == edgeIndex && spriteMeshView.IsActionActive(MeshEditorAction.CreateVertex) ||
spriteMeshView.closestEdge == edgeIndex && spriteMeshView.IsActionActive(MeshEditorAction.SplitEdge) ||
edgeIndex == m_EdgeIntersectionResult.intersectEdgeIndex && spriteMeshView.IsActionActive(MeshEditorAction.CreateEdge);
}
private void PreviewCreateVertex()
{
if (spriteMeshView.mode == SpriteMeshViewMode.CreateVertex &&
spriteMeshView.IsActionActive(MeshEditorAction.CreateVertex))
{
Vector2 clampedMousePos = ClampToFrame(spriteMeshView.mouseWorldPosition);
if (spriteMeshView.hoveredEdge != -1)
{
Edge edge = m_SpriteMeshData.edges[spriteMeshView.hoveredEdge];
spriteMeshView.BeginDrawEdges();
spriteMeshView.DrawEdge(m_SpriteMeshData.GetPosition(edge.index1), clampedMousePos);
spriteMeshView.DrawEdge(m_SpriteMeshData.GetPosition(edge.index2), clampedMousePos);
spriteMeshView.EndDrawEdges();
}
spriteMeshView.DrawVertex(clampedMousePos);
}
}
private void PreviewCreateEdge()
{
if (!spriteMeshView.IsActionActive(MeshEditorAction.CreateEdge))
return;
spriteMeshView.BeginDrawEdges();
spriteMeshView.DrawEdge(m_SpriteMeshData.GetPosition(m_EdgeIntersectionResult.startVertexIndex), m_EdgeIntersectionResult.endPosition);
if (m_EdgeIntersectionResult.intersectEdgeIndex != -1)
{
Edge intersectingEdge = m_SpriteMeshData.edges[m_EdgeIntersectionResult.intersectEdgeIndex];
spriteMeshView.DrawEdge(m_SpriteMeshData.GetPosition(intersectingEdge.index1), m_EdgeIntersectionResult.endPosition);
spriteMeshView.DrawEdge(m_SpriteMeshData.GetPosition(intersectingEdge.index2), m_EdgeIntersectionResult.endPosition);
}
spriteMeshView.EndDrawEdges();
if (m_EdgeIntersectionResult.endVertexIndex == -1)
spriteMeshView.DrawVertex(m_EdgeIntersectionResult.endPosition);
}
private void PreviewSplitEdge()
{
if (!spriteMeshView.IsActionActive(MeshEditorAction.SplitEdge))
return;
Vector2 clampedMousePos = ClampToFrame(spriteMeshView.mouseWorldPosition);
Edge closestEdge = m_SpriteMeshData.edges[spriteMeshView.closestEdge];
spriteMeshView.BeginDrawEdges();
spriteMeshView.DrawEdge(m_SpriteMeshData.GetPosition(closestEdge.index1), clampedMousePos);
spriteMeshView.DrawEdge(m_SpriteMeshData.GetPosition(closestEdge.index2), clampedMousePos);
spriteMeshView.EndDrawEdges();
spriteMeshView.DrawVertex(clampedMousePos);
}
private void DrawVertices()
{
for (int i = 0; i < m_SpriteMeshData.vertexCount; i++)
{
Vector3 position = m_SpriteMeshData.GetPosition(i);
if (selection.Contains(i))
spriteMeshView.DrawVertexSelected(position);
else if (i == spriteMeshView.hoveredVertex && spriteMeshView.IsActionHot(MeshEditorAction.None))
spriteMeshView.DrawVertexHovered(position);
else
spriteMeshView.DrawVertex(position);
}
}
private void HandleSelectVertex()
{
bool additive;
if (spriteMeshView.DoSelectVertex(out additive))
SelectVertex(spriteMeshView.hoveredVertex, additive);
}
private void HandleSelectEdge()
{
bool additive;
if (spriteMeshView.DoSelectEdge(out additive))
SelectEdge(spriteMeshView.hoveredEdge, additive);
}
private void HandleMoveVertex()
{
if(spriteMeshView.IsActionTriggered(MeshEditorAction.MoveVertex))
m_Moved = false;
Vector2 delta;
if (spriteMeshView.DoMoveVertex(out delta))
{
if(!m_Moved)
{
cacheUndo.BeginUndoOperation(TextContent.moveVertices);
m_Moved = true;
}
MoveSelectedVertices(delta);
}
}
private void HandleCreateVertex()
{
if (spriteMeshView.DoCreateVertex())
CreateVertex(spriteMeshView.mouseWorldPosition, spriteMeshView.hoveredEdge);
}
private void HandleSplitEdge()
{
if (spriteMeshView.DoSplitEdge())
SplitEdge(spriteMeshView.mouseWorldPosition, spriteMeshView.closestEdge);
}
private void HandleCreateEdge()
{
if (spriteMeshView.DoCreateEdge())
CreateEdge(spriteMeshView.mouseWorldPosition, spriteMeshView.hoveredVertex, spriteMeshView.hoveredEdge);
}
private void HandleMoveEdge()
{
if(spriteMeshView.IsActionTriggered(MeshEditorAction.MoveEdge))
m_Moved = false;
Vector2 delta;
if (spriteMeshView.DoMoveEdge(out delta))
{
if(!m_Moved)
{
cacheUndo.BeginUndoOperation(TextContent.moveVertices);
m_Moved = true;
}
MoveSelectedVertices(delta);
}
}
private void HandleRemoveEdge()
{
Edge edge;
if (GetSelectedEdge(out edge) && spriteMeshView.DoRemove())
RemoveEdge(edge);
}
private void HandleRemoveVertices()
{
if (spriteMeshView.DoRemove())
RemoveSelectedVertices();
}
private void CreateVertex(Vector2 position, int edgeIndex)
{
position = MathUtility.ClampPositionToRect(position, frame);
cacheUndo.BeginUndoOperation(TextContent.createVertex);
BoneWeight boneWeight = new BoneWeight();
Vector3Int indices;
Vector3 barycentricCoords;
if (m_SpriteMeshDataController.FindTriangle(position, out indices, out barycentricCoords))
{
EditableBoneWeight bw1 = m_SpriteMeshData.GetWeight(indices.x);
EditableBoneWeight bw2 = m_SpriteMeshData.GetWeight(indices.y);
EditableBoneWeight bw3 = m_SpriteMeshData.GetWeight(indices.z);
EditableBoneWeight result = new EditableBoneWeight();
foreach (BoneWeightChannel channel in bw1)
{
if (!channel.enabled)
continue;
var weight = channel.weight * barycentricCoords.x;
if (weight > 0f)
result.AddChannel(channel.boneIndex, weight, true);
}
foreach (BoneWeightChannel channel in bw2)
{
if (!channel.enabled)
continue;
var weight = channel.weight * barycentricCoords.y;
if (weight > 0f)
result.AddChannel(channel.boneIndex, weight, true);
}
foreach (BoneWeightChannel channel in bw3)
{
if (!channel.enabled)
continue;
var weight = channel.weight * barycentricCoords.z;
if (weight > 0f)
result.AddChannel(channel.boneIndex, weight, true);
}
result.UnifyChannelsWithSameBoneIndex();
result.FilterChannels(0f);
result.Clamp(4, true);
boneWeight = result.ToBoneWeight(true);
}
else if (edgeIndex != -1)
{
Edge edge = m_SpriteMeshData.edges[edgeIndex];
Vector2 pos1 = m_SpriteMeshData.GetPosition(edge.index1);
Vector2 pos2 = m_SpriteMeshData.GetPosition(edge.index2);
Vector2 dir1 = (position - pos1);
Vector2 dir2 = (pos2 - pos1);
float t = Vector2.Dot(dir1, dir2.normalized) / dir2.magnitude;
t = Mathf.Clamp01(t);
BoneWeight bw1 = m_SpriteMeshData.GetWeight(edge.index1).ToBoneWeight(true);
BoneWeight bw2 = m_SpriteMeshData.GetWeight(edge.index2).ToBoneWeight(true);
boneWeight = EditableBoneWeightUtility.Lerp(bw1, bw2, t);
}
m_SpriteMeshDataController.CreateVertex(position, edgeIndex);
m_SpriteMeshData.GetWeight(m_SpriteMeshData.vertexCount - 1).SetFromBoneWeight(boneWeight);
Triangulate();
}
private void SelectVertex(int index, bool additiveToggle)
{
if (index < 0)
throw new ArgumentException("Index out of range");
bool selected = selection.Contains(index);
if (selected)
{
if (additiveToggle)
{
cacheUndo.BeginUndoOperation(TextContent.selection);
selection.Select(index, false);
}
}
else
{
cacheUndo.BeginUndoOperation(TextContent.selection);
if (!additiveToggle)
ClearSelection();
selection.Select(index, true);
}
cacheUndo.IncrementCurrentGroup();
}
private void SelectEdge(int index, bool additiveToggle)
{
Debug.Assert(index >= 0);
Edge edge = m_SpriteMeshData.edges[index];
cacheUndo.BeginUndoOperation(TextContent.selection);
bool selected = selection.Contains(edge.index1) && selection.Contains(edge.index2);
if (selected)
{
if (additiveToggle)
{
selection.Select(edge.index1, false);
selection.Select(edge.index2, false);
}
}
else
{
if (!additiveToggle)
ClearSelection();
selection.Select(edge.index1, true);
selection.Select(edge.index2, true);
}
cacheUndo.IncrementCurrentGroup();
}
private void ClearSelection()
{
cacheUndo.BeginUndoOperation(TextContent.selection);
selection.Clear();
}
private void MoveSelectedVertices(Vector2 delta)
{
delta = MathUtility.MoveRectInsideFrame(CalculateRectFromSelection(), frame, delta);
var indices = selection.elements;
foreach (int index in indices)
{
Vector2 v = m_SpriteMeshData.GetPosition(index);
m_SpriteMeshData.SetPosition(index, ClampToFrame(v + delta));
}
Triangulate();
}
private void CreateEdge(Vector2 position, int hoveredVertexIndex, int hoveredEdgeIndex)
{
position = ClampToFrame(position);
EdgeIntersectionResult edgeIntersectionResult = CalculateEdgeIntersection(selection.activeElement, hoveredVertexIndex, hoveredEdgeIndex, position);
cacheUndo.BeginUndoOperation(TextContent.createEdge);
int selectIndex = -1;
if (edgeIntersectionResult.endVertexIndex == -1)
{
CreateVertex(edgeIntersectionResult.endPosition, edgeIntersectionResult.intersectEdgeIndex);
m_SpriteMeshDataController.CreateEdge(selection.activeElement, m_SpriteMeshData.vertexCount - 1);
selectIndex = m_SpriteMeshData.vertexCount - 1;
}
else
{
m_SpriteMeshDataController.CreateEdge(selection.activeElement, edgeIntersectionResult.endVertexIndex);
Triangulate();
selectIndex = edgeIntersectionResult.endVertexIndex;
}
ClearSelection();
selection.Select(selectIndex, true);
cacheUndo.IncrementCurrentGroup();
}
private void SplitEdge(Vector2 position, int edgeIndex)
{
cacheUndo.BeginUndoOperation(TextContent.splitEdge);
Vector2 clampedMousePos = ClampToFrame(position);
CreateVertex(clampedMousePos, edgeIndex);
cacheUndo.IncrementCurrentGroup();
}
private bool GetSelectedEdge(out Edge edge)
{
edge = default(Edge);
if (selection.Count != 2)
return false;
var indices = selection.elements;
int index1 = indices[0];
int index2 = indices[1];
edge = new Edge(index1, index2);
if (!m_SpriteMeshData.edges.Contains(edge))
return false;
return true;
}
private void RemoveEdge(Edge edge)
{
cacheUndo.BeginUndoOperation(TextContent.removeEdge);
m_SpriteMeshDataController.RemoveEdge(edge);
Triangulate();
}
private void RemoveSelectedVertices()
{
cacheUndo.BeginUndoOperation(TextContent.removeVertices);
m_SpriteMeshDataController.RemoveVertex(selection.elements);
Triangulate();
selection.Clear();
}
private void Triangulate()
{
m_SpriteMeshDataController.Triangulate(triangulator);
m_SpriteMeshDataController.SortTrianglesByDepth();
}
private Vector2 ClampToFrame(Vector2 position)
{
return MathUtility.ClampPositionToRect(position, frame);
}
private Rect CalculateRectFromSelection()
{
Rect rect = new Rect();
Vector2 min = new Vector2(float.MaxValue, float.MaxValue);
Vector2 max = new Vector2(float.MinValue, float.MinValue);
var indices = selection.elements;
foreach (int index in indices)
{
Vector2 v = m_SpriteMeshData.GetPosition(index);
min.x = Mathf.Min(min.x, v.x);
min.y = Mathf.Min(min.y, v.y);
max.x = Mathf.Max(max.x, v.x);
max.y = Mathf.Max(max.y, v.y);
}
rect.min = min;
rect.max = max;
return rect;
}
private void UpdateEdgeInstersection()
{
if (selection.Count == 1)
m_EdgeIntersectionResult = CalculateEdgeIntersection(selection.activeElement, spriteMeshView.hoveredVertex, spriteMeshView.hoveredEdge, ClampToFrame(spriteMeshView.mouseWorldPosition));
}
private EdgeIntersectionResult CalculateEdgeIntersection(int vertexIndex, int hoveredVertexIndex, int hoveredEdgeIndex, Vector2 targetPosition)
{
Debug.Assert(vertexIndex >= 0);
EdgeIntersectionResult edgeIntersection = new EdgeIntersectionResult();
edgeIntersection.startVertexIndex = vertexIndex;
edgeIntersection.endVertexIndex = hoveredVertexIndex;
edgeIntersection.endPosition = targetPosition;
edgeIntersection.intersectEdgeIndex = -1;
Vector2 startPoint = m_SpriteMeshData.GetPosition(edgeIntersection.startVertexIndex);
bool intersectsEdge = false;
int lastIntersectingEdgeIndex = -1;
do
{
lastIntersectingEdgeIndex = edgeIntersection.intersectEdgeIndex;
if (intersectsEdge)
{
Vector2 dir = edgeIntersection.endPosition - startPoint;
edgeIntersection.endPosition += dir.normalized * 10f;
}
intersectsEdge = SegmentIntersectsEdge(startPoint, edgeIntersection.endPosition, vertexIndex, ref edgeIntersection.endPosition, out edgeIntersection.intersectEdgeIndex);
//if we are hovering a vertex and intersect an edge indexing it we forget about the intersection
if (intersectsEdge && m_SpriteMeshData.edges[edgeIntersection.intersectEdgeIndex].Contains(edgeIntersection.endVertexIndex))
{
edgeIntersection.intersectEdgeIndex = -1;
intersectsEdge = false;
edgeIntersection.endPosition = m_SpriteMeshData.GetPosition(edgeIntersection.endVertexIndex);
}
if (intersectsEdge)
{
edgeIntersection.endVertexIndex = -1;
Edge intersectingEdge = m_SpriteMeshData.edges[edgeIntersection.intersectEdgeIndex];
Vector2 newPointScreen = spriteMeshView.WorldToScreen(edgeIntersection.endPosition);
Vector2 edgeV1 = spriteMeshView.WorldToScreen(m_SpriteMeshData.GetPosition(intersectingEdge.index1));
Vector2 edgeV2 = spriteMeshView.WorldToScreen(m_SpriteMeshData.GetPosition(intersectingEdge.index2));
if ((newPointScreen - edgeV1).magnitude <= kSnapDistance)
edgeIntersection.endVertexIndex = intersectingEdge.index1;
else if ((newPointScreen - edgeV2).magnitude <= kSnapDistance)
edgeIntersection.endVertexIndex = intersectingEdge.index2;
if (edgeIntersection.endVertexIndex != -1)
{
edgeIntersection.intersectEdgeIndex = -1;
intersectsEdge = false;
edgeIntersection.endPosition = m_SpriteMeshData.GetPosition(edgeIntersection.endVertexIndex);
}
}
}
while (intersectsEdge && lastIntersectingEdgeIndex != edgeIntersection.intersectEdgeIndex);
edgeIntersection.intersectEdgeIndex = intersectsEdge ? edgeIntersection.intersectEdgeIndex : hoveredEdgeIndex;
if (edgeIntersection.endVertexIndex != -1 && !intersectsEdge)
edgeIntersection.endPosition = m_SpriteMeshData.GetPosition(edgeIntersection.endVertexIndex);
return edgeIntersection;
}
private bool SegmentIntersectsEdge(Vector2 p1, Vector2 p2, int ignoreIndex, ref Vector2 point, out int intersectingEdgeIndex)
{
intersectingEdgeIndex = -1;
float sqrDistance = float.MaxValue;
for (int i = 0; i < m_SpriteMeshData.edges.Count; i++)
{
Edge edge = m_SpriteMeshData.edges[i];
Vector2 v1 = m_SpriteMeshData.GetPosition(edge.index1);
Vector2 v2 = m_SpriteMeshData.GetPosition(edge.index2);
Vector2 pointTmp = Vector2.zero;
if (!edge.Contains(ignoreIndex) && MathUtility.SegmentIntersection(p1, p2, v1, v2, ref pointTmp))
{
float sqrMagnitude = (pointTmp - p1).sqrMagnitude;
if (sqrMagnitude < sqrDistance)
{
sqrDistance = sqrMagnitude;
intersectingEdgeIndex = i;
point = pointTmp;
}
}
}
return intersectingEdgeIndex != -1;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5796720807c5b4856aea84babbabd4ee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,539 @@
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class SpriteMeshView : ISpriteMeshView
{
readonly int m_VertexHashCode = "Vertex".GetHashCode();
readonly int m_EdgeHashCode = "Edge".GetHashCode();
const string kDeleteCommandName = "Delete";
const string kSoftDeleteCommandName = "SoftDelete";
static readonly Color kEdgeColor = Color.cyan;
static readonly Color kEdgeHoveredColor = Color.yellow;
static readonly Color kEdgeSelectedColor = Color.yellow;
const float kEdgeWidth = 2f;
const float kVertexRadius = 2.5f;
private class Styles
{
public readonly GUIStyle pointNormalStyle;
public readonly GUIStyle pointHoveredStyle;
public readonly GUIStyle pointSelectedStyle;
public Styles()
{
Texture2D pointNormal = ResourceLoader.Load<Texture2D>("SkinningModule/dotCyan.png");
Texture2D pointHovered = ResourceLoader.Load<Texture2D>("SkinningModule/dotYellow.png");
Texture2D pointSelected = ResourceLoader.Load<Texture2D>("SkinningModule/dotYellow.png");
pointNormalStyle = new GUIStyle();
pointNormalStyle.normal.background = pointNormal;
pointNormalStyle.fixedWidth = 8f;
pointNormalStyle.fixedHeight = 8f;
pointHoveredStyle = new GUIStyle();
pointHoveredStyle.normal.background = pointHovered;
pointHoveredStyle.fixedWidth = 10f;
pointHoveredStyle.fixedHeight = 10f;
pointSelectedStyle = new GUIStyle();
pointSelectedStyle.normal.background = pointSelected;
pointSelectedStyle.fixedWidth = 10f;
pointSelectedStyle.fixedHeight = 10f;
}
}
private Styles m_Styles;
private Styles styles
{
get
{
if (m_Styles == null)
m_Styles = new Styles();
return m_Styles;
}
}
int m_HoveredEdge = -1;
int m_HoveredEdgeControlID = -1;
int m_MoveEdgeControlID = -1;
int m_HoveredVertex = -1;
int m_PrevHoveredVertex = -1;
int m_HoveredVertexControlID = -1;
int m_MoveVertexControlID = -1;
Color m_TempColor;
SliderData m_HotSliderData = SliderData.zero;
MeshEditorAction m_PreviousActiveAction = MeshEditorAction.None;
private Vector2 m_MouseWorldPosition;
private float m_NearestVertexDistance;
private float m_NearestEdgeDistance;
private int m_NearestVertex = -1;
private int m_NearestEdge = -1;
public SpriteMeshViewMode mode { get; set; }
public ISelection<int> selection { get; set; }
public int defaultControlID { get; set; }
public Rect frame { get; set; }
private IGUIWrapper guiWrapper { get; set; }
public Vector2 mouseWorldPosition
{
get { return m_MouseWorldPosition; }
}
public int hoveredVertex
{
get { return m_HoveredVertex; }
}
public int hoveredEdge
{
get { return m_HoveredEdge; }
}
public int closestEdge
{
get { return m_NearestEdge; }
}
public SpriteMeshView(IGUIWrapper gw)
{
guiWrapper = gw;
}
public void CancelMode()
{
if (mode != SpriteMeshViewMode.EditGeometry)
{
if (guiWrapper.IsKeyDown(KeyCode.Escape) || guiWrapper.IsMouseDown(1))
{
mode = SpriteMeshViewMode.EditGeometry;
guiWrapper.UseCurrentEvent();
}
}
}
public void BeginLayout()
{
var vertexControlID = guiWrapper.GetControlID(m_VertexHashCode, FocusType.Passive);
var edgeControlID = guiWrapper.GetControlID(m_EdgeHashCode, FocusType.Passive);
if (guiWrapper.eventType == EventType.Layout || guiWrapper.eventType == EventType.MouseMove)
{
m_NearestVertexDistance = float.MaxValue;
m_NearestEdgeDistance = float.MaxValue;
m_NearestVertex = -1;
m_NearestEdge = -1;
m_MouseWorldPosition = guiWrapper.GUIToWorld(guiWrapper.mousePosition);
m_HoveredVertexControlID = vertexControlID;
m_HoveredEdgeControlID = edgeControlID;
m_PrevHoveredVertex = m_HoveredVertex;
m_HoveredVertex = -1;
m_HoveredEdge = -1;
if (guiWrapper.IsControlHot(0))
{
m_MoveVertexControlID = -1;
m_MoveEdgeControlID = -1;
}
}
}
public void EndLayout()
{
guiWrapper.LayoutControl(m_HoveredEdgeControlID, m_NearestEdgeDistance);
guiWrapper.LayoutControl(m_HoveredVertexControlID, m_NearestVertexDistance);
if(guiWrapper.IsControlNearest(m_HoveredVertexControlID))
m_HoveredVertex = m_NearestVertex;
if (guiWrapper.IsControlNearest(m_HoveredEdgeControlID))
m_HoveredEdge = m_NearestEdge;
if (guiWrapper.eventType == EventType.Layout || guiWrapper.eventType == EventType.MouseMove)
if (m_PrevHoveredVertex != m_HoveredVertex)
guiWrapper.Repaint();
}
public void LayoutVertex(Vector2 position, int index)
{
if (guiWrapper.eventType == EventType.Layout)
{
var distance = guiWrapper.DistanceToCircle(position, kVertexRadius);
if (distance <= m_NearestVertexDistance)
{
m_NearestVertexDistance = distance;
m_NearestVertex = index;
}
}
}
public void LayoutEdge(Vector2 startPosition, Vector2 endPosition, int index)
{
if (guiWrapper.eventType == EventType.Layout)
{
var distance = guiWrapper.DistanceToSegment(startPosition, endPosition);
if (distance < m_NearestEdgeDistance)
{
m_NearestEdgeDistance = distance;
m_NearestEdge = index;
}
}
}
public bool DoCreateVertex()
{
if (mode == SpriteMeshViewMode.CreateVertex && IsActionActive(MeshEditorAction.CreateVertex))
ConsumeMouseMoveEvents();
if (IsActionTriggered(MeshEditorAction.CreateVertex))
{
guiWrapper.SetGuiChanged(true);
guiWrapper.UseCurrentEvent();
return true;
}
return false;
}
public bool DoSelectVertex(out bool additive)
{
additive = false;
if (IsActionTriggered(MeshEditorAction.SelectVertex))
{
additive = guiWrapper.isActionKeyDown;
guiWrapper.Repaint();
return true;
}
return false;
}
public bool DoMoveVertex(out Vector2 delta)
{
delta = Vector2.zero;
if (IsActionTriggered(MeshEditorAction.MoveVertex))
{
m_MoveVertexControlID = m_HoveredVertexControlID;
m_HotSliderData.position = mouseWorldPosition;
}
Vector3 newPosition;
if (guiWrapper.DoSlider(m_MoveVertexControlID, m_HotSliderData, out newPosition))
{
delta = newPosition - m_HotSliderData.position;
m_HotSliderData.position = newPosition;
return true;
}
return false;
}
public bool DoMoveEdge(out Vector2 delta)
{
delta = Vector2.zero;
if (IsActionTriggered(MeshEditorAction.MoveEdge))
{
m_MoveEdgeControlID = m_HoveredEdgeControlID;
m_HotSliderData.position = mouseWorldPosition;
}
Vector3 newPosition;
if (guiWrapper.DoSlider(m_MoveEdgeControlID, m_HotSliderData, out newPosition))
{
delta = newPosition - m_HotSliderData.position;
m_HotSliderData.position = newPosition;
return true;
}
return false;
}
public bool DoCreateEdge()
{
if (IsActionActive(MeshEditorAction.CreateEdge))
ConsumeMouseMoveEvents();
if (IsActionTriggered(MeshEditorAction.CreateEdge))
{
guiWrapper.SetGuiChanged(true);
guiWrapper.UseCurrentEvent();
return true;
}
return false;
}
public bool DoSplitEdge()
{
if (IsActionActive(MeshEditorAction.SplitEdge))
ConsumeMouseMoveEvents();
if (IsActionTriggered(MeshEditorAction.SplitEdge))
{
guiWrapper.UseCurrentEvent();
guiWrapper.SetGuiChanged(true);
return true;
}
return false;
}
public bool DoSelectEdge(out bool additive)
{
additive = false;
if (IsActionTriggered(MeshEditorAction.SelectEdge))
{
additive = guiWrapper.isActionKeyDown;
guiWrapper.Repaint();
return true;
}
return false;
}
public bool DoRemove()
{
if (IsActionTriggered(MeshEditorAction.Remove))
{
guiWrapper.UseCurrentEvent();
guiWrapper.SetGuiChanged(true);
return true;
}
return false;
}
public void DrawVertex(Vector2 position)
{
DrawingUtility.DrawGUIStyleCap(0, position, Quaternion.identity, 1f, styles.pointNormalStyle);
}
public void DrawVertexHovered(Vector2 position)
{
DrawingUtility.DrawGUIStyleCap(0, position, Quaternion.identity, 1f, styles.pointHoveredStyle);
}
public void DrawVertexSelected(Vector2 position)
{
DrawingUtility.DrawGUIStyleCap(0, position, Quaternion.identity, 1f, styles.pointSelectedStyle);
}
public void BeginDrawEdges()
{
if (guiWrapper.eventType != EventType.Repaint)
return;
DrawingUtility.BeginSolidLines();
m_TempColor = Handles.color;
}
public void EndDrawEdges()
{
if (guiWrapper.eventType != EventType.Repaint)
return;
DrawingUtility.EndLines();
Handles.color = m_TempColor;
}
public void DrawEdge(Vector2 startPosition, Vector2 endPosition)
{
DrawEdge(startPosition, endPosition, kEdgeColor);
}
public void DrawEdgeHovered(Vector2 startPosition, Vector2 endPosition)
{
DrawEdge(startPosition, endPosition, kEdgeHoveredColor);
}
public void DrawEdgeSelected(Vector2 startPosition, Vector2 endPosition)
{
DrawEdge(startPosition, endPosition, kEdgeSelectedColor);
}
public bool IsActionActive(MeshEditorAction action)
{
if (guiWrapper.isAltDown || !guiWrapper.IsControlHot(0))
return false;
var canCreateEdge = CanCreateEdge();
var canSplitEdge = CanSplitEdge();
if (action == MeshEditorAction.None)
return guiWrapper.IsControlNearest(defaultControlID);
if (action == MeshEditorAction.CreateVertex)
{
if(!frame.Contains(mouseWorldPosition))
return false;
if (mode == SpriteMeshViewMode.EditGeometry)
return guiWrapper.IsControlNearest(defaultControlID);
if (mode == SpriteMeshViewMode.CreateVertex)
return hoveredVertex == -1;
}
if (action == MeshEditorAction.MoveVertex)
return guiWrapper.IsControlNearest(m_HoveredVertexControlID);
if (action == MeshEditorAction.CreateEdge)
return canCreateEdge;
if (action == MeshEditorAction.SplitEdge)
return canSplitEdge;
if (action == MeshEditorAction.MoveEdge)
return guiWrapper.IsControlNearest(m_HoveredEdgeControlID);
if (action == MeshEditorAction.SelectVertex)
return guiWrapper.IsControlNearest(m_HoveredVertexControlID);
if (action == MeshEditorAction.SelectEdge)
return mode == SpriteMeshViewMode.EditGeometry &&
guiWrapper.IsControlNearest(m_HoveredEdgeControlID) &&
!canCreateEdge && !canSplitEdge;
if (action == MeshEditorAction.Remove)
return true;
return false;
}
public bool IsActionHot(MeshEditorAction action)
{
if (action == MeshEditorAction.None)
return guiWrapper.IsControlHot(0);
if (action == MeshEditorAction.MoveVertex)
return guiWrapper.IsControlHot(m_HoveredVertexControlID);
if (action == MeshEditorAction.MoveEdge)
return guiWrapper.IsControlHot(m_HoveredEdgeControlID);
return false;
}
public bool IsActionTriggered(MeshEditorAction action)
{
if (!IsActionActive(action))
return false;
if (action == MeshEditorAction.CreateVertex)
{
if (mode == SpriteMeshViewMode.EditGeometry)
return guiWrapper.IsMouseDown(0) && guiWrapper.clickCount == 2;
}
if (action == MeshEditorAction.Remove)
{
if ((guiWrapper.eventType == EventType.ValidateCommand || guiWrapper.eventType == EventType.ExecuteCommand)
&& (guiWrapper.commandName == kSoftDeleteCommandName || guiWrapper.commandName == kDeleteCommandName))
{
if (guiWrapper.eventType == EventType.ExecuteCommand)
return true;
guiWrapper.UseCurrentEvent();
}
return false;
}
if(action != MeshEditorAction.None)
return guiWrapper.IsMouseDown(0);
return false;
}
public Vector2 WorldToScreen(Vector2 position)
{
return HandleUtility.WorldToGUIPoint(position);
}
private void ConsumeMouseMoveEvents()
{
if (guiWrapper.eventType == EventType.MouseMove || (guiWrapper.eventType == EventType.MouseDrag && guiWrapper.mouseButton == 0))
guiWrapper.UseCurrentEvent();
}
private bool CanCreateEdge()
{
if(!frame.Contains(mouseWorldPosition) || !(guiWrapper.IsControlNearest(defaultControlID) || guiWrapper.IsControlNearest(m_HoveredVertexControlID) || guiWrapper.IsControlNearest(m_HoveredEdgeControlID)))
return false;
if (mode == SpriteMeshViewMode.EditGeometry)
return guiWrapper.isShiftDown && selection.Count == 1 && !selection.Contains(hoveredVertex);
if (mode == SpriteMeshViewMode.CreateEdge)
return selection.Count == 1 && !selection.Contains(hoveredVertex);
return false;
}
private bool CanSplitEdge()
{
if(!frame.Contains(mouseWorldPosition) || !(guiWrapper.IsControlNearest(defaultControlID) || guiWrapper.IsControlNearest(m_HoveredEdgeControlID)))
return false;
if (mode == SpriteMeshViewMode.EditGeometry)
return guiWrapper.isShiftDown && m_NearestEdge != -1 && hoveredVertex == -1 && selection.Count == 0;
if (mode == SpriteMeshViewMode.SplitEdge)
return m_NearestEdge != -1 && hoveredVertex == -1;
return false;
}
private void DrawEdge(Vector2 startPosition, Vector2 endPosition, Color color)
{
if (guiWrapper.eventType != EventType.Repaint)
return;
Handles.color = color;
float width = kEdgeWidth / Handles.matrix.m00;
DrawingUtility.DrawSolidLine(width, startPosition, endPosition);
}
public void DoRepaint()
{
if(guiWrapper.eventType != EventType.Layout)
return;
var action = MeshEditorAction.None;
if(IsActionActive(MeshEditorAction.CreateVertex))
action = MeshEditorAction.CreateVertex;
else if(IsActionActive(MeshEditorAction.CreateEdge))
action = MeshEditorAction.CreateEdge;
else if(IsActionActive(MeshEditorAction.SplitEdge))
action = MeshEditorAction.SplitEdge;
if(m_PreviousActiveAction != action)
{
m_PreviousActiveAction = action;
guiWrapper.Repaint();
}
}
public bool CanRepaint()
{
return guiWrapper.eventType == EventType.Repaint;
}
public bool CanLayout()
{
return guiWrapper.eventType == EventType.Layout;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 07512ec0d03c84285a2573a5747097d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,33 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class UnselectTool<T>
{
private Unselector<T> m_Unselector = new Unselector<T>();
public ICacheUndo cacheUndo { get; set; }
public ISelection<T> selection
{
get { return m_Unselector.selection; }
set { m_Unselector.selection = value; }
}
public Action onUnselect = () => {};
public void OnGUI()
{
Debug.Assert(cacheUndo != null);
Debug.Assert(selection != null);
var e = Event.current;
if (selection.Count > 0 && e.type == EventType.MouseDown && e.button == 1 && !e.alt)
{
cacheUndo.BeginUndoOperation(TextContent.clearSelection);
m_Unselector.Select();
e.Use();
onUnselect.Invoke();
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 61f1168dfbac54f04b6068f199c35704
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,129 @@
using UnityEngine;
using UnityEditor.U2D.Sprites;
namespace UnityEditor.U2D.Animation
{
internal class WeightInspector
{
private SpriteMeshDataController m_SpriteMeshDataController = new SpriteMeshDataController();
private GUIContent[] m_BoneNameContents;
public ISpriteMeshData spriteMeshData
{
get { return m_SpriteMeshDataController.spriteMeshData; }
set
{
if (spriteMeshData != value)
m_SpriteMeshDataController.spriteMeshData = value;
}
}
public GUIContent[] boneNames
{
get { return m_BoneNameContents; }
set { m_BoneNameContents = value; }
}
public ICacheUndo cacheUndo { get; set; }
public ISelection<int> selection { get; set; }
public int controlID { get { return 0; } }
private bool m_UndoRegistered = false;
protected ISpriteEditor spriteEditor
{
get; private set;
}
public void OnInspectorGUI()
{
ChannelsGUI();
}
private void ChannelsGUI()
{
if (GUIUtility.hotControl == 0)
m_UndoRegistered = false;
for (int channel = 0; channel < 4; ++channel)
{
var enabled = false;
var boneIndex = -1;
var weight = 0f;
var isChannelEnabledMixed = false;
var isBoneIndexMixed = false;
var isWeightMixed = false;
if (spriteMeshData != null)
m_SpriteMeshDataController.GetMultiEditChannelData(selection, channel, out enabled, out boneIndex, out weight, out isChannelEnabledMixed, out isBoneIndexMixed, out isWeightMixed);
var newEnabled = enabled;
var newBoneIndex = boneIndex;
var newWeight = weight;
EditorGUI.BeginChangeCheck();
WeightChannelDrawer(ref newEnabled, ref newBoneIndex, ref newWeight, isChannelEnabledMixed, isBoneIndexMixed, isWeightMixed);
if (EditorGUI.EndChangeCheck())
{
RegisterUndo();
m_SpriteMeshDataController.SetMultiEditChannelData(selection, channel, enabled, newEnabled, boneIndex, newBoneIndex, weight, newWeight);
}
}
}
private void WeightChannelDrawer(
ref bool isChannelEnabled, ref int boneIndex, ref float weight,
bool isChannelEnabledMixed = false, bool isBoneIndexMixed = false, bool isWeightMixed = false)
{
EditorGUILayout.BeginHorizontal();
EditorGUIUtility.fieldWidth = 1f;
EditorGUIUtility.labelWidth = 1f;
EditorGUI.showMixedValue = isChannelEnabledMixed;
isChannelEnabled = EditorGUILayout.Toggle(GUIContent.none, isChannelEnabled);
EditorGUIUtility.fieldWidth = 30f;
EditorGUIUtility.labelWidth = 30f;
using (new EditorGUI.DisabledScope(!isChannelEnabled && !isChannelEnabledMixed))
{
int tempBoneIndex = GUI.enabled ? boneIndex : -1;
EditorGUI.BeginChangeCheck();
EditorGUIUtility.fieldWidth = 80f;
EditorGUI.showMixedValue = GUI.enabled && isBoneIndexMixed;
tempBoneIndex = EditorGUILayout.Popup(tempBoneIndex, m_BoneNameContents);
if (EditorGUI.EndChangeCheck())
boneIndex = tempBoneIndex;
EditorGUIUtility.fieldWidth = 32f;
EditorGUI.showMixedValue = isWeightMixed;
weight = EditorGUILayout.Slider(GUIContent.none, weight, 0f, 1f);
}
EditorGUILayout.EndHorizontal();
EditorGUI.showMixedValue = false;
EditorGUIUtility.labelWidth = -1;
EditorGUIUtility.fieldWidth = -1;
}
private void RegisterUndo()
{
if (m_UndoRegistered)
return;
Debug.Assert(cacheUndo != null);
cacheUndo.BeginUndoOperation(TextContent.editWeights);
m_UndoRegistered = true;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3610f44c4cf884dad93f89fe4f19b8db
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: