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,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;
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: a31658f0a7411474fa4e2be61c4f9df2
timeCreated: 1503758178
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,137 @@
using UnityEditor;
using UnityEngine;
using UnityEditor.Sprites;
using System.Collections;
using System.Collections.Generic;
namespace UnityEditor.U2D
{
public class AngleRangeGUI
{
public static readonly int kLeftHandleHashCode = "LeftHandle".GetHashCode();
public static readonly int kRightHandleHashCode = "RightHandle".GetHashCode();
public const float kRangeWidth = 10f;
public static void AngleRangeField(Rect rect, ref float start, ref float end, float angleOffset, float radius, bool snap, bool drawLine, bool drawCircle, Color rangeColor)
{
var leftId = GUIUtility.GetControlID(kLeftHandleHashCode, FocusType.Passive);
var rightId = GUIUtility.GetControlID(kRightHandleHashCode, FocusType.Passive);
AngleRangeField(rect, leftId, rightId, ref start, ref end, angleOffset, radius, snap, drawLine, drawCircle, rangeColor);
}
public static void AngleRangeField(Rect rect, int leftHandleID, int rightHandleID, ref float start, ref float end, float angleOffset, float radius, bool snap, bool drawLine, bool drawCircle, Color rangeColor)
{
Color activeColor = Handles.color;
if (Event.current.type == EventType.Repaint)
{
float range = end - start;
Color color = Handles.color;
Handles.color = rangeColor;
if (range < 0f)
Handles.color = Color.red;
SpriteShapeHandleUtility.DrawSolidArc(rect.center, Vector3.forward, Quaternion.AngleAxis(start + angleOffset, Vector3.forward) * Vector3.right, range, radius, kRangeWidth);
Handles.color = color;
}
EditorGUI.BeginChangeCheck();
float handleSize = 15f;
start = AngleField(rect, leftHandleID, start, angleOffset, new Vector2(-3.5f, -7.5f), start + angleOffset + 90f, handleSize, radius, snap, drawLine, drawCircle, SpriteShapeHandleUtility.RangeLeftCap);
if (EditorGUI.EndChangeCheck())
start = Mathf.Clamp(start, end - 360f, end);
EditorGUI.BeginChangeCheck();
end = AngleField(rect, rightHandleID, end, angleOffset, new Vector2(3.5f, -7.5f), end + angleOffset + 90f, handleSize, radius, snap, drawLine, false, SpriteShapeHandleUtility.RangeRightCap);
if (EditorGUI.EndChangeCheck())
end = Mathf.Clamp(end, end, start + 360f);
Handles.color = activeColor;
}
public static void AngleRangeField(Rect rect, SerializedProperty startProperty, SerializedProperty endProperty, float angleOffset, float radius, bool snap, bool drawLine, bool drawCircle, Color rangeColor)
{
var start = startProperty.floatValue;
var end = endProperty.floatValue;
EditorGUI.BeginChangeCheck();
AngleRangeField(rect, ref start, ref end, angleOffset, radius, snap, drawLine, drawCircle, rangeColor);
if (EditorGUI.EndChangeCheck())
{
startProperty.floatValue = start;
endProperty.floatValue = end;
}
}
public static void AngleField(int id, SerializedProperty property, float angleOffset, Vector2 handleOffset, float handleAngle, float handleSize, float radius, bool snap, bool drawLine, bool drawCircle, Handles.CapFunction drawCapFunction)
{
EditorGUI.BeginChangeCheck();
float value = AngleField(id, property.floatValue, angleOffset, handleOffset, handleAngle, handleSize, radius, snap, drawLine, drawCircle, drawCapFunction);
if (EditorGUI.EndChangeCheck())
{
property.floatValue = value;
}
}
public static void AngleField(Rect r, int id, SerializedProperty property, float angleOffset, Vector2 handleOffset, float handleAngle, float handleSize, float radius, bool snap, bool drawLine, bool drawCircle, Handles.CapFunction drawCapFunction)
{
EditorGUI.BeginChangeCheck();
float value = AngleField(r, id, property.floatValue, angleOffset, handleOffset, handleAngle, handleSize, radius, snap, drawLine, drawCircle, drawCapFunction);
if (EditorGUI.EndChangeCheck())
{
property.floatValue = value;
}
}
public static float AngleField(int id, float angle, float angleOffset, Vector2 handleOffset, float handleAngle, float radius, float handleSize, bool snap, bool drawLine, bool drawCircle, Handles.CapFunction drawCapFunction)
{
Rect rect = EditorGUILayout.GetControlRect(false, radius * 2f);
return AngleField(rect, id, angle, angleOffset, handleOffset, handleAngle, radius, handleSize, snap, drawLine, drawCircle, drawCapFunction);
}
public static float AngleField(Rect rect, int id, float angle, float angleOffset, Vector2 handleOffset, float handleAngle, float handleSize, float radius, bool snap, bool drawLine, bool drawCircle, Handles.CapFunction drawCapFunction)
{
float offsetedAngle = angle + angleOffset;
Vector2 pos = new Vector2(Mathf.Cos(offsetedAngle * Mathf.Deg2Rad), Mathf.Sin(offsetedAngle * Mathf.Deg2Rad)) * radius + rect.center;
if (Event.current.type == EventType.Repaint)
{
if (drawCircle)
Handles.DrawWireDisc(rect.center, Vector3.forward, radius);
if (drawLine)
Handles.DrawLine(rect.center, pos);
}
if (GUI.enabled)
{
EditorGUI.BeginChangeCheck();
Quaternion rotation = Quaternion.AngleAxis(handleAngle, Vector3.forward);
Vector2 posNew = SpriteShapeHandleUtility.Slider2D(id, pos, rotation * handleOffset, rotation, handleSize, drawCapFunction);
if (EditorGUI.EndChangeCheck())
{
Vector2 v1 = pos - rect.center;
Vector2 v2 = posNew - rect.center;
float angleDirection = Mathf.Sign(Vector3.Dot(Vector3.forward, Vector3.Cross(v1, v2)));
float angleIncrement = Vector2.Angle(v1, v2);
angle += angleIncrement * angleDirection;
if (snap)
angle = Mathf.RoundToInt(angle);
}
}
return angle;
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: c5b7a6d3ca9063e4faeefb6613a86c7c
timeCreated: 1503758178
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,336 @@
using UnityEditor;
using UnityEngine;
using UnityEditor.Sprites;
using System.Collections;
using System.Collections.Generic;
namespace UnityEditor.U2D
{
public enum AngleRangeAction
{
SelectRange,
ModifyRange,
CreateRange,
ModifySelector,
RemoveRange,
}
public interface IAngleRangeView
{
int hoveredRangeIndex { get; }
void RequestFocusIndex(int index);
float GetAngleFromPosition(Rect rect, float angleOffset);
void Repaint();
void SetupLayout(Rect rect, float angleOffset, float radius);
bool DoAngleRange(int index, Rect rect, float radius, float angleOffset, ref float start, ref float end, bool snap, bool disabled, Color gradientMin, Color gradientMid, Color gradientMax);
bool DoSelectAngleRange(int currentSelected, out int newSelected);
bool DoCreateRange(Rect rect, float radius, float angleOffset, float start, float end);
void DoCreateRangeTooltip();
bool DoSelector(Rect rect, float angleOffset, float radius, float angle, out float newAngle);
bool DoRemoveRange();
bool IsActionActive(AngleRangeAction action);
bool IsActionTriggering(AngleRangeAction action);
bool IsActionFinishing(AngleRangeAction action);
void DrawAngleRangeOutline(Rect rect, float start, float end, float angleOffset, float radius);
}
public class AngleRangeView : IAngleRangeView
{
const string kDeleteCommandName = "Delete";
const string kSoftDeleteCommandName = "SoftDelete";
static readonly int kAngleRangeHashCode = "AngleRange".GetHashCode();
static readonly int kCreateRangeHashCode = "CreateRange".GetHashCode();
static readonly int kSelectorHashCode = "Selector".GetHashCode();
private static Color kHightlightColor = new Color(0.25f, 0.5f, 1.0f);
private static Color kNoKeboardFocusColor = new Color(0.3f, 0.5f, 0.65f);
private static class Contents
{
public static readonly GUIContent addRangeTooltip = new GUIContent("", "Click to add a new range");
}
private int m_FocusedRangeControlID = -1;
private int m_HoveredRangeIndex = -1;
private int m_HoveredRangeID = -1;
private int m_HoveredHandleID = -1;
private int m_HotHandleID = -1;
private int m_CreateRangeControlID = -1;
private int m_SelectorControlID = -1;
private int m_RequestFocusIndex = -1;
public int hoveredRangeIndex { get { return m_HoveredRangeIndex; } }
public void RequestFocusIndex(int index)
{
GUIUtility.keyboardControl = 0;
m_RequestFocusIndex = index;
}
public float GetAngleFromPosition(Rect rect, float angleOffset)
{
return Mathf.RoundToInt(SpriteShapeHandleUtility.PosToAngle(Event.current.mousePosition, rect.center, -angleOffset));
}
public void Repaint()
{
HandleUtility.Repaint();
}
public void SetupLayout(Rect rect, float angleOffset, float radius)
{
m_CreateRangeControlID = GUIUtility.GetControlID(kCreateRangeHashCode, FocusType.Passive);
m_SelectorControlID = GUIUtility.GetControlID(kSelectorHashCode, FocusType.Passive);
LayoutCreateRange(rect, angleOffset, radius);
if (Event.current.type == EventType.Layout)
{
m_HoveredRangeIndex = -1;
m_HoveredRangeID = -1;
m_HoveredHandleID = -1;
if (GUIUtility.hotControl == 0)
{
m_HotHandleID = -1;
}
}
}
private void LayoutCreateRange(Rect rect, float angleOffset, float radius)
{
if (Event.current.type == EventType.Layout)
{
var mousePosition = Event.current.mousePosition;
var distance = SpriteShapeHandleUtility.DistanceToArcWidth(mousePosition, rect.center, 0f, 360f, radius, AngleRangeGUI.kRangeWidth, angleOffset);
HandleUtility.AddControl(m_CreateRangeControlID, distance);
}
}
public bool DoAngleRange(int index, Rect rect, float radius, float angleOffset, ref float start, ref float end, bool snap, bool disabled, Color gradientMin, Color gradientMid, Color gradientMax)
{
var changed = false;
var controlID = GUIUtility.GetControlID(kAngleRangeHashCode, FocusType.Passive);
var leftHandleId = GUIUtility.GetControlID(AngleRangeGUI.kLeftHandleHashCode, FocusType.Passive);
var rightHandleId = GUIUtility.GetControlID(AngleRangeGUI.kRightHandleHashCode, FocusType.Passive);
if (Event.current.type == EventType.Layout)
{
var distance = SpriteShapeHandleUtility.DistanceToArcWidth(Event.current.mousePosition, rect.center, start, end, radius, AngleRangeGUI.kRangeWidth, angleOffset);
HandleUtility.AddControl(controlID, distance);
if (HandleUtility.nearestControl == controlID)
{
m_HoveredRangeIndex = index;
m_HoveredRangeID = controlID;
}
}
if (IsActionTriggering(AngleRangeAction.ModifyRange))
{
m_HotHandleID = m_HoveredHandleID;
GrabKeyboardFocus(controlID);
}
if (m_RequestFocusIndex == index)
{
GrabKeyboardFocus(controlID);
if (Event.current.type == EventType.Repaint)
m_RequestFocusIndex = -1;
}
using (new EditorGUI.DisabledScope(disabled))
{
var midAngle = (end - start) * 0.5f + start;
var t = 2f * (midAngle + 180f) / 360f;
var color = gradientMin;
if (t < 1f)
color = Color.Lerp(gradientMin, gradientMid, t);
else
color = Color.Lerp(gradientMid, gradientMax, t - 1f);
if (!disabled)
{
color = kNoKeboardFocusColor;
if (HasKeyboardFocus())
color = kHightlightColor;
}
EditorGUI.BeginChangeCheck();
AngleRangeGUI.AngleRangeField(rect, leftHandleId, rightHandleId, ref start, ref end, angleOffset, radius, snap, false, false, color);
changed = EditorGUI.EndChangeCheck();
}
//Extra Layout from handles
if (Event.current.type == EventType.Layout &&
(HandleUtility.nearestControl == leftHandleId || HandleUtility.nearestControl == rightHandleId))
{
m_HoveredRangeIndex = index;
m_HoveredRangeID = controlID;
m_HoveredHandleID = HandleUtility.nearestControl;
}
return changed;
}
public bool DoSelectAngleRange(int currentSelected, out int newSelected)
{
newSelected = currentSelected;
if (IsActionTriggering(AngleRangeAction.SelectRange))
{
newSelected = m_HoveredRangeIndex;
GUI.changed = true;
Repaint();
HandleUtility.nearestControl = m_SelectorControlID;
return true;
}
return false;
}
public bool DoCreateRange(Rect rect, float radius, float angleOffset, float start, float end)
{
if (IsActionTriggering(AngleRangeAction.CreateRange))
{
GUI.changed = true;
HandleUtility.nearestControl = m_SelectorControlID;
return true;
}
if (IsActionActive(AngleRangeAction.CreateRange))
{
DrawAngleRangeOutline(rect, start, end, angleOffset, radius);
if (Event.current.type == EventType.MouseMove)
Repaint();
}
return false;
}
public void DoCreateRangeTooltip()
{
if (IsActionActive(AngleRangeAction.CreateRange))
{
var mousePosition = Event.current.mousePosition;
EditorGUI.LabelField(new Rect(mousePosition, new Vector2(1f, 20f)), Contents.addRangeTooltip);
}
}
public bool DoSelector(Rect rect, float angleOffset, float radius, float angle, out float newAngle)
{
EditorGUI.BeginChangeCheck();
newAngle = AngleRangeGUI.AngleField(rect, m_SelectorControlID, angle, angleOffset, Vector2.down * 7.5f, angle, 15f, radius - AngleRangeGUI.kRangeWidth, true, true, false, SpriteShapeHandleUtility.PlayHeadCap);
return EditorGUI.EndChangeCheck();
}
public bool DoRemoveRange()
{
EventType eventType = Event.current.type;
if (IsActionTriggering(AngleRangeAction.RemoveRange))
{
Event.current.Use();
GUI.changed = true;
return true;
}
return false;
}
public bool IsActionActive(AngleRangeAction action)
{
if (GUIUtility.hotControl != 0)
return false;
if (action == AngleRangeAction.SelectRange)
return HandleUtility.nearestControl == m_HoveredRangeID;
if (action == AngleRangeAction.ModifyRange)
return HandleUtility.nearestControl == m_HoveredHandleID;
if (action == AngleRangeAction.CreateRange)
return HandleUtility.nearestControl == m_CreateRangeControlID;
if (action == AngleRangeAction.ModifySelector)
return HandleUtility.nearestControl == m_SelectorControlID;
if (action == AngleRangeAction.RemoveRange)
return HasKeyboardFocus();
return false;
}
public bool IsActionHot(AngleRangeAction action)
{
if (GUIUtility.hotControl == 0)
return false;
if (action == AngleRangeAction.ModifyRange)
return GUIUtility.hotControl == m_HotHandleID;
return false;
}
public bool IsActionTriggering(AngleRangeAction action)
{
if (!IsActionActive(action))
return false;
EventType eventType = Event.current.type;
if (action == AngleRangeAction.RemoveRange)
{
if ((eventType == EventType.ValidateCommand || eventType == EventType.ExecuteCommand)
&& (Event.current.commandName == kSoftDeleteCommandName || Event.current.commandName == kDeleteCommandName))
{
if (eventType == EventType.ExecuteCommand)
return true;
Event.current.Use();
}
return false;
}
return eventType == EventType.MouseDown && Event.current.button == 0;
}
public bool IsActionFinishing(AngleRangeAction action)
{
if (!IsActionHot(action))
return false;
return (Event.current.type == EventType.MouseUp && Event.current.button == 0) || Event.current.type == EventType.Ignore;
}
public void DrawAngleRangeOutline(Rect rect, float start, float end, float angleOffset, float radius)
{
if (Event.current.type == EventType.Repaint)
SpriteShapeHandleUtility.DrawRangeOutline(start, end, angleOffset, rect.center, radius, AngleRangeGUI.kRangeWidth - 1f);
}
private void GrabKeyboardFocus(int controlID)
{
m_FocusedRangeControlID = controlID;
GUIUtility.keyboardControl = controlID;
}
private bool HasKeyboardFocus()
{
return GUIUtility.keyboardControl == m_FocusedRangeControlID;
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 56b5f4e1cb3304201b11247e0fb1eec7
timeCreated: 1503758178
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,43 @@
using UnityEngine;
using UnityEngine.U2D;
using UnityEditor.U2D.SpriteShape;
namespace UnityEditor.U2D
{
public class ContextMenu
{
private static AngleRange CreateAngleRange(float start, float end, int order)
{
AngleRange angleRange = new AngleRange();
angleRange.start = start;
angleRange.end = end;
angleRange.order = order;
return angleRange;
}
[MenuItem("Assets/Create/Sprite Shape Profile/Open Shape", false, 358)]
public static void CreateNewSpriteStrip()
{
UnityEngine.U2D.SpriteShape newSpriteShape = SpriteShapeEditorUtility.CreateSpriteShapeAsset();
newSpriteShape.angleRanges.Add(CreateAngleRange(-180.0f, 180.0f, 0));
}
[MenuItem("Assets/Create/Sprite Shape Profile/Closed Shape", false, 359)]
public static void CreateNewSpriteShape()
{
UnityEngine.U2D.SpriteShape newSpriteShape = SpriteShapeEditorUtility.CreateSpriteShapeAsset();
newSpriteShape.angleRanges.Add(CreateAngleRange(-45.0f, 45.0f, 4));
newSpriteShape.angleRanges.Add(CreateAngleRange(-135.0f, -45.0f, 3));
newSpriteShape.angleRanges.Add(CreateAngleRange(135.0f, 225.0f, 2));
newSpriteShape.angleRanges.Add(CreateAngleRange(45.0f, 135.0f, 1));
}
[MenuItem("GameObject/2D Object/Sprite Shape")]
internal static void CreateSpriteShapeEmpty()
{
SpriteShapeEditorUtility.SetShapeFromAsset(SpriteShapeEditorUtility.CreateSpriteShapeControllerFromSelection());
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 98a4cc9d9dadb844e8669b0665d53897
timeCreated: 1503992201
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,236 @@
using UnityEditor;
using UnityEngine;
using UnityEditor.Sprites;
using System.Collections;
using System.Collections.Generic;
namespace UnityEditor.U2D
{
public static class EditorSpriteGUIUtility
{
public enum FitMode
{
BestFit,
FitHorizontal,
FitVertical,
Fill,
Tiled
}
private static Material s_SpriteMaterial;
public static Material spriteMaterial
{
get
{
if (s_SpriteMaterial == null)
{
s_SpriteMaterial = new Material(Shader.Find("Hidden/InternalSpritesInspector"));
s_SpriteMaterial.hideFlags = HideFlags.DontSave;
}
s_SpriteMaterial.SetFloat("_AdjustLinearForGamma", PlayerSettings.colorSpace == ColorSpace.Linear ? 1.0f : 0.0f);
return s_SpriteMaterial;
}
}
public static Texture GetOriginalSpriteTexture(Sprite sprite)
{
return UnityEditor.Sprites.SpriteUtility.GetSpriteTexture(sprite, false);
}
public static Vector2[] GetOriginalSpriteUvs(Sprite sprite)
{
return UnityEditor.Sprites.SpriteUtility.GetSpriteUVs(sprite, false);
}
public static void DrawSpriteInRectPrepare(Rect rect, Sprite sprite, FitMode fitMode, bool excludeBorders, bool forceQuad, Mesh mesh)
{
var vertices = new List<Vector3>();
var uvs = new List<Vector2>();
var indices = new List<int>();
mesh.Clear();
if (!sprite)
{
mesh.UploadMeshData(false);
return;
}
Vector2 scale = Vector2.one;
Rect spriteRect = sprite.textureRect;
Vector2 bottomLeftBorderOffset = sprite.rect.position + new Vector2(sprite.border.x, sprite.border.y) - spriteRect.position;
Vector2 topRightBorderOffset = new Vector2(sprite.border.z, sprite.border.w) + (spriteRect.position + spriteRect.size) - (sprite.rect.position + sprite.rect.size);
if (excludeBorders)
{
forceQuad = true;
spriteRect.position = spriteRect.position + bottomLeftBorderOffset;
spriteRect.size = spriteRect.size - bottomLeftBorderOffset - topRightBorderOffset;
}
bool tiled = false;
if (fitMode == FitMode.Tiled)
{
tiled = true;
forceQuad = true;
fitMode = FitMode.BestFit;
}
if (fitMode == FitMode.BestFit)
{
float spriteRatio = spriteRect.width / spriteRect.height;
float frameRatio = rect.width / rect.height;
if (spriteRatio < frameRatio)
fitMode = FitMode.FitVertical;
else
fitMode = FitMode.FitHorizontal;
}
if (fitMode == FitMode.FitHorizontal)
scale = Vector2.one * (rect.width / spriteRect.width);
if (fitMode == FitMode.FitVertical)
scale = Vector2.one * (rect.height / spriteRect.height);
if (fitMode == FitMode.Fill)
{
scale.x = rect.width / spriteRect.width;
scale.y = rect.height / spriteRect.height;
}
Texture spriteTexture = GetOriginalSpriteTexture(sprite);
if (spriteTexture == null)
return;
if (forceQuad)
{
Vector2 uvScale = new Vector2(1f / spriteTexture.width, 1f / spriteTexture.height);
Vector2 uvPos = Vector2.Scale(spriteRect.position, uvScale);
Vector2 uvSize = Vector2.Scale(spriteRect.size, uvScale);
Vector2 uv0 = uvPos;
Vector2 uv1 = uvPos + Vector2.up * uvSize.y;
Vector2 uv2 = uvPos + Vector2.right * uvSize.x;
Vector2 uv3 = uvPos + uvSize;
Vector3 v0 = new Vector3(uv0.x * spriteTexture.width - spriteRect.position.x - spriteRect.width * 0.5f, uv0.y * spriteTexture.height - spriteRect.position.y - spriteRect.height * 0.5f, 0f);
Vector3 v1 = new Vector3(uv1.x * spriteTexture.width - spriteRect.position.x - spriteRect.width * 0.5f, uv1.y * spriteTexture.height - spriteRect.position.y - spriteRect.height * 0.5f, 0f);
Vector3 v2 = new Vector3(uv2.x * spriteTexture.width - spriteRect.position.x - spriteRect.width * 0.5f, uv2.y * spriteTexture.height - spriteRect.position.y - spriteRect.height * 0.5f, 0f);
Vector3 v3 = new Vector3(uv3.x * spriteTexture.width - spriteRect.position.x - spriteRect.width * 0.5f, uv3.y * spriteTexture.height - spriteRect.position.y - spriteRect.height * 0.5f, 0f);
v0 = Vector3.Scale(v0, scale);
v1 = Vector3.Scale(v1, scale);
v2 = Vector3.Scale(v2, scale);
v3 = Vector3.Scale(v3, scale);
//TODO: Support vertical tiling when horizontal fitted
if (tiled && fitMode == FitMode.FitVertical)
{
Vector2 scaledRectSize = Vector2.Scale(rect.size, new Vector2(1f / scale.x, 1f / scale.y));
float halfDistanceToFill = (scaledRectSize.x - spriteRect.width) * 0.5f;
int halfFillSegmentCount = (int)Mathf.Ceil(halfDistanceToFill / spriteRect.width);
int segmentCount = halfFillSegmentCount * 2 + 1;
int vertexCount = segmentCount * 4;
vertices.Capacity = vertexCount;
uvs.Capacity = vertexCount;
indices.Capacity = vertexCount;
Vector3 offset = Vector3.zero;
Vector3 offsetStep = Vector3.Scale(Vector3.right * spriteRect.width, scale);
float distanceStep = spriteRect.width;
float distanceToFill = halfDistanceToFill + distanceStep;
int vertexIndex = 0;
for (int i = 0; i <= halfFillSegmentCount; ++i)
{
float t = Mathf.Clamp01(distanceToFill / spriteRect.width);
uvs.Add(uv0);
uvs.Add(uv1);
uvs.Add(Vector3.Lerp(uv0, uv2, t));
uvs.Add(Vector3.Lerp(uv1, uv3, t));
vertices.Add(v0 + offset);
vertices.Add(v1 + offset);
vertices.Add(Vector3.Lerp(v0, v2, t) + offset);
vertices.Add(Vector3.Lerp(v1, v3, t) + offset);
indices.Add(vertexIndex);
indices.Add(vertexIndex + 2);
indices.Add(vertexIndex + 1);
indices.Add(vertexIndex + 2);
indices.Add(vertexIndex + 3);
indices.Add(vertexIndex + 1);
vertexIndex += 4;
if (i > 0)
{
uvs.Add(Vector2.Lerp(uv0, uv2, 1f - t));
uvs.Add(Vector2.Lerp(uv1, uv3, 1f - t));
uvs.Add(uv2);
uvs.Add(uv3);
vertices.Add(Vector3.Lerp(v0, v2, 1f - t) - offset);
vertices.Add(Vector3.Lerp(v1, v3, 1f - t) - offset);
vertices.Add(v2 - offset);
vertices.Add(v3 - offset);
indices.Add(vertexIndex);
indices.Add(vertexIndex + 2);
indices.Add(vertexIndex + 1);
indices.Add(vertexIndex + 2);
indices.Add(vertexIndex + 3);
indices.Add(vertexIndex + 1);
vertexIndex += 4;
}
offset += offsetStep;
distanceToFill -= distanceStep;
}
}
else
{
vertices.AddRange(new Vector3[] { v0, v1, v2, v3 });
uvs.AddRange(new Vector2[] { uv0, uv1, uv2, uv3 });
indices.AddRange(new int[] { 0, 2, 1, 2, 3, 1 });
}
}
else
{
ushort[] triangles = sprite.triangles;
indices.Capacity = triangles.Length;
for (int i = 0; i < triangles.Length; ++i)
indices.Add((int)triangles[i]);
uvs.AddRange(GetOriginalSpriteUvs(sprite));
vertices.Capacity = uvs.Count;
for (int i = 0; i < uvs.Count; ++i)
{
Vector3 v = new Vector3(uvs[i].x * spriteTexture.width - spriteRect.position.x - spriteRect.width * 0.5f, uvs[i].y * spriteTexture.height - spriteRect.position.y - spriteRect.height * 0.5f, 0f);
vertices.Add(Vector3.Scale(v, scale));
}
}
mesh.SetVertices(vertices);
mesh.SetUVs(0, uvs);
mesh.SetTriangles(indices, 0);
mesh.UploadMeshData(false);
}
public static void DrawMesh(Mesh mesh, Material material, Vector3 position, Quaternion rotation, Vector3 scale)
{
if (Event.current.type != EventType.Repaint)
return;
Matrix4x4 matrix = new Matrix4x4();
matrix.SetTRS(position, rotation, scale);
material.SetPass(0);
Graphics.DrawMeshNow(mesh, matrix);
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: aff60f81fc1eab749a82103779466d07
timeCreated: 1503758178
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 15cbf89e8ba92694cb870a55b60f1b81
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2ba760cb26319f14f86529637445de30
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,83 @@
// Texture is forced to be in Gamma space regardless of the active ColorSpace.
Shader "Hidden/InternalSpritesInspector"
{
Properties
{
[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
_Color("Tint", Color) = (1, 1, 1, 1)
[MaterialToggle] PixelSnap("Pixel snap", Float) = 0
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "True"
"RenderType" = "Transparent"
"PreviewType" = "Plane"
"CanUseSpriteAtlas" = "True"
}
Cull Off
Lighting Off
ZWrite Off
Fog{ Mode Off }
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile DUMMY PIXELSNAP_ON
#include "UnityCG.cginc"
uniform bool _AdjustLinearForGamma;
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
half2 texcoord : TEXCOORD0;
float2 clipUV : TEXCOORD1;
};
fixed4 _Color;
uniform float4x4 unity_GUIClipTextureMatrix;
v2f vert(appdata_t IN)
{
float3 screenUV = UnityObjectToViewPos(IN.vertex);
v2f OUT;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
OUT.clipUV = mul(unity_GUIClipTextureMatrix, float4(screenUV.xy, 0, 1.0));
return OUT;
}
sampler2D _MainTex;
sampler2D _GUIClipTexture;
fixed4 frag(v2f IN) : COLOR
{
fixed4 col = tex2D(_MainTex, IN.texcoord);
fixed alpha = col.a;
if (_AdjustLinearForGamma)
col.rgb = LinearToGammaSpace(col.rgb);
col.a = alpha * tex2D(_GUIClipTexture, IN.clipUV).a;
return col * IN.color;
}
ENDCG
}
}
}

View file

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 603d454d711fe784cba9ce08dd22b881
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,91 @@
fileFormatVersion: 2
guid: 9417efc47083f4a1598c1966a6345cdb
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -0,0 +1,91 @@
fileFormatVersion: 2
guid: 9ea72647c24be493ba6f15a9cd2a24ae
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,91 @@
fileFormatVersion: 2
guid: ee5df01235032491c8b180741ea820fe
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 574ba49617df66b40a29fe7f0b185aab
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -0,0 +1,107 @@
fileFormatVersion: 2
guid: 0a9a0f36a52ce7f4d813fbf5d8f76a1c
timeCreated: 1505457322
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 1
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: -1
mipBias: -1
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 0
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- buildTarget: tvOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -0,0 +1,107 @@
fileFormatVersion: 2
guid: d1508e1dc42abb745b24c8891a614d2a
timeCreated: 1505457322
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 1
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: -1
mipBias: -1
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 0
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- buildTarget: tvOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,244 @@
using UnityEngine;
using UnityEngine.U2D;
using System.Collections.Generic;
using UnityEditor.Experimental.SceneManagement;
using UnityEditor.U2D.SpriteShape;
using Object = UnityEngine.Object;
namespace UnityEditor.U2D
{
[InitializeOnLoad]
public static class SceneDragAndDrop
{
static SceneDragAndDrop()
{
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui += OnSceneGUI;
EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyGUI;
#else
SceneView.onSceneGUIDelegate += OnSceneGUI;
#endif
}
static class Contents
{
public static readonly string createString = "Create Sprite Shape";
}
static List<Object> s_SceneDragObjects;
static DragType s_DragType;
enum DragType { NotInitialized, CreateMultiple }
public delegate string ShowFileDialogDelegate(string title, string defaultName, string extension, string message, string defaultPath);
static void OnSceneGUI(SceneView sceneView)
{
HandleSceneDrag(sceneView, Event.current, DragAndDrop.objectReferences, DragAndDrop.paths);
}
public static GameObject Create(UnityEngine.U2D.SpriteShape shape, Vector3 position, SceneView sceneView)
{
string name = string.IsNullOrEmpty(shape.name) ? "New SpriteShapeController" : shape.name;
name = GameObjectUtility.GetUniqueNameForSibling(null, name);
GameObject go = new GameObject(name);
SpriteShapeController shapeController = go.AddComponent<SpriteShapeController>();
shapeController.spriteShape = shape;
go.transform.position = position;
go.hideFlags = HideFlags.HideAndDontSave;
return go;
}
static void OnHierarchyGUI(int instanceID, Rect rect)
{
HandleSceneDrag(null, Event.current, DragAndDrop.objectReferences, null);
}
static List<UnityEngine.U2D.SpriteShape> GetSpriteShapeFromPathsOrObjects(Object[] objects, string[] paths, EventType currentEventType)
{
List<UnityEngine.U2D.SpriteShape> result = new List<UnityEngine.U2D.SpriteShape>();
foreach (Object obj in objects)
{
if (AssetDatabase.Contains(obj))
{
if (obj is UnityEngine.U2D.SpriteShape)
result.Add(obj as UnityEngine.U2D.SpriteShape);
}
}
return result;
}
static void HandleSceneDrag(SceneView sceneView, Event evt, Object[] objectReferences, string[] paths)
{
if (evt.type != EventType.DragUpdated && evt.type != EventType.DragPerform && evt.type != EventType.DragExited)
return;
switch (evt.type)
{
case EventType.DragUpdated:
{
DragType newDragType = DragType.CreateMultiple;
if (s_DragType != newDragType || s_SceneDragObjects == null)
// Either this is first time we are here OR evt.alt changed during drag
{
if (ExistingAssets(objectReferences)) // External drag with images that are not in the project
{
List<UnityEngine.U2D.SpriteShape> assets = GetSpriteShapeFromPathsOrObjects(objectReferences, paths,
evt.type);
if (assets.Count == 0)
return;
if (s_DragType != DragType.NotInitialized)
// evt.alt changed during drag, so we need to cleanup and start over
CleanUp(true);
s_DragType = newDragType;
CreateSceneDragObjects(assets);
}
}
if (s_SceneDragObjects != null)
{
if (sceneView != null)
PositionSceneDragObjects(s_SceneDragObjects, sceneView, evt.mousePosition);
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
evt.Use();
}
}
break;
case EventType.DragPerform:
{
List<UnityEngine.U2D.SpriteShape> assets = GetSpriteShapeFromPathsOrObjects(objectReferences, paths, evt.type);
if (assets.Count > 0 && s_SceneDragObjects != null)
{
// For external drags, we have delayed all creation to DragPerform because only now we have the imported sprite assets
if (s_SceneDragObjects.Count == 0)
{
CreateSceneDragObjects(assets);
if (sceneView != null)
PositionSceneDragObjects(s_SceneDragObjects, sceneView, evt.mousePosition);
}
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
foreach (GameObject dragGO in s_SceneDragObjects)
{
if (prefabStage != null)
{
var parTransform = Selection.activeTransform != null
? Selection.activeTransform
: prefabStage.prefabContentsRoot.transform;
dragGO.transform.SetParent(parTransform, true);
}
Undo.RegisterCreatedObjectUndo(dragGO, "Create Shape");
dragGO.hideFlags = HideFlags.None;
}
Selection.objects = s_SceneDragObjects.ToArray();
CleanUp(false);
evt.Use();
}
}
break;
case EventType.DragExited:
{
if (s_SceneDragObjects != null)
{
CleanUp(true);
evt.Use();
}
}
break;
}
}
static void PositionSceneDragObjects(List<Object> objects, SceneView sceneView, Vector2 mousePosition)
{
Vector3 position = Vector3.zero;
position = HandleUtility.GUIPointToWorldRay(mousePosition).GetPoint(10);
if (sceneView.in2DMode)
{
position.z = 0f;
}
else
{
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
object hit = HandleUtility.RaySnap(HandleUtility.GUIPointToWorldRay(mousePosition));
if (hit != null)
{
RaycastHit rh = (RaycastHit)hit;
position = rh.point;
}
}
foreach (GameObject gameObject in objects)
{
gameObject.transform.position = position;
}
}
static void CreateSceneDragObjects(List<UnityEngine.U2D.SpriteShape> shapes)
{
if (s_SceneDragObjects == null)
s_SceneDragObjects = new List<Object>();
if (s_DragType == DragType.CreateMultiple)
{
foreach (UnityEngine.U2D.SpriteShape sprite in shapes)
s_SceneDragObjects.Add(CreateDragGO(sprite, Vector3.zero));
}
else
{
s_SceneDragObjects.Add(CreateDragGO(shapes[0], Vector3.zero));
}
}
static void CleanUp(bool deleteTempSceneObject)
{
if (deleteTempSceneObject)
{
foreach (GameObject gameObject in s_SceneDragObjects)
Object.DestroyImmediate(gameObject, false);
}
if (s_SceneDragObjects != null)
{
s_SceneDragObjects.Clear();
s_SceneDragObjects = null;
}
s_DragType = DragType.NotInitialized;
}
static bool ExistingAssets(Object[] objects)
{
foreach (Object obj in objects)
{
if (AssetDatabase.Contains(obj))
return true;
}
return false;
}
static GameObject CreateDragGO(UnityEngine.U2D.SpriteShape spriteShape, Vector3 position)
{
SpriteShapeController spriteShapeController = SpriteShapeEditorUtility.CreateSpriteShapeController(spriteShape);
GameObject gameObject = spriteShapeController.gameObject;
gameObject.transform.position = position;
gameObject.hideFlags = HideFlags.HideAndDontSave;
spriteShapeController.spriteShape = spriteShape;
SpriteShapeEditorUtility.SetShapeFromAsset(spriteShapeController);
return gameObject;
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: cd24657e741f79a4685b9a4a0b23b5b5
timeCreated: 1504685300
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,312 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D
{
internal class SpriteSelector
{
int m_SelectedSprite = 0;
Sprite[] m_SpriteList = null;
Texture[] m_Thumbnails;
Vector2 m_ScrollPos;
public int selectedIndex
{
get { return m_SelectedSprite; }
set { m_SelectedSprite = value; }
}
internal static class Styles
{
public static GUIStyle gridList = "GridList";
public static GUIContent spriteList = EditorGUIUtility.TrTextContent("Sprite Variant");
public static GUIContent missingSprites = EditorGUIUtility.TrTextContent("No brushes defined.");
public static GUIStyle localGrid = null;
}
public SpriteSelector()
{
m_SpriteList = null;
}
public void UpdateSprites(Sprite[] sprites)
{
m_SpriteList = sprites;
UpdateSelection(0);
}
public void UpdateSelection(int newSelectedBrush)
{
m_SelectedSprite = newSelectedBrush;
}
private static int CalcTotalHorizSpacing(int xCount, GUIStyle style, GUIStyle firstStyle, GUIStyle midStyle, GUIStyle lastStyle)
{
if (xCount < 2)
return 0;
if (xCount == 2)
return Mathf.Max(firstStyle.margin.right, lastStyle.margin.left);
int internalSpace = Mathf.Max(midStyle.margin.left, midStyle.margin.right);
return Mathf.Max(firstStyle.margin.right, midStyle.margin.left) + Mathf.Max(midStyle.margin.right, lastStyle.margin.left) + internalSpace * (xCount - 3);
}
// Helper function: Get all mouse rects
private static Rect[] CalcMouseRects(Rect position, GUIContent[] contents, int xCount, float elemWidth, float elemHeight, GUIStyle style, GUIStyle firstStyle, GUIStyle midStyle, GUIStyle lastStyle, bool addBorders, GUI.ToolbarButtonSize buttonSize)
{
int count = contents.Length;
int x = 0;
float xPos = position.xMin, yPos = position.yMin;
GUIStyle currentStyle = style;
Rect[] retval = new Rect[count];
if (count > 1)
currentStyle = firstStyle;
for (int i = 0; i < count; i++)
{
float w = 0;
switch (buttonSize)
{
case GUI.ToolbarButtonSize.Fixed:
w = elemWidth;
break;
case GUI.ToolbarButtonSize.FitToContents:
w = currentStyle.CalcSize(contents[i]).x;
break;
}
if (!addBorders)
retval[i] = new Rect(xPos, yPos, w, elemHeight);
else
retval[i] = currentStyle.margin.Add(new Rect(xPos, yPos, w, elemHeight));
//we round the values to the dpi-aware pixel grid
retval[i] = GUIUtility.AlignRectToDevice(retval[i]);
GUIStyle nextStyle = midStyle;
if (i == count - 2 || i == xCount - 2)
nextStyle = lastStyle;
xPos = retval[i].xMax + Mathf.Max(currentStyle.margin.right, nextStyle.margin.left);
x++;
if (x >= xCount)
{
x = 0;
yPos += elemHeight + Mathf.Max(style.margin.top, style.margin.bottom);
xPos = position.xMin;
nextStyle = firstStyle;
}
currentStyle = nextStyle;
}
return retval;
}
static void DrawRectangleOutline(Rect rect, Color color)
{
Color currentColor = Handles.color;
Handles.color = color;
// Draw viewport outline
Vector3[] points = new Vector3[5];
points[0] = new Vector3(rect.x, rect.y, 0.0f);
points[1] = new Vector3(rect.x + rect.width, rect.y, 0.0f);
points[2] = new Vector3(rect.x + rect.width, rect.y + rect.height, 0.0f);
points[3] = new Vector3(rect.x, rect.y + rect.height, 0.0f);
points[4] = new Vector3(rect.x, rect.y, 0.0f);
Handles.DrawPolyLine(points);
Handles.color = currentColor;
}
// Make a button grid
private static int DoButtonGrid(Rect position, int selected, GUIContent[] contents, string[] controlNames, int xCount, GUIStyle style, GUIStyle firstStyle, GUIStyle midStyle, GUIStyle lastStyle, GUI.ToolbarButtonSize buttonSize, bool[] contentsEnabled = null)
{
int count = contents.Length;
if (count == 0)
return selected;
if (xCount <= 0)
{
Debug.LogWarning("You are trying to create a SelectionGrid with zero or less elements to be displayed in the horizontal direction. Set xCount to a positive value.");
return selected;
}
if (contentsEnabled != null && contentsEnabled.Length != count)
throw new ArgumentException("contentsEnabled");
// Figure out how large each element should be
int rows = count / xCount;
if (count % xCount != 0)
rows++;
float totalHorizSpacing = CalcTotalHorizSpacing(xCount, style, firstStyle, midStyle, lastStyle);
float totalVerticalSpacing = Mathf.Max(style.margin.top, style.margin.bottom) * (rows - 1);
float elemWidth = (position.width - totalHorizSpacing) / xCount;
float elemHeight = (position.height - totalVerticalSpacing) / rows;
if (style.fixedWidth != 0)
elemWidth = style.fixedWidth;
if (style.fixedHeight != 0)
elemHeight = style.fixedHeight;
Rect[] buttonRects = CalcMouseRects(position, contents, xCount, elemWidth, elemHeight, style, firstStyle, midStyle, lastStyle, false, buttonSize);
GUIStyle selectedButtonStyle = null;
int selectedButtonID = 0;
for (int buttonIndex = 0; buttonIndex < count; ++buttonIndex)
{
bool wasEnabled = GUI.enabled;
GUI.enabled &= (contentsEnabled == null || contentsEnabled[buttonIndex]);
var buttonRect = buttonRects[buttonIndex];
var content = contents[buttonIndex];
if (controlNames != null)
GUI.SetNextControlName(controlNames[buttonIndex]);
var id = GUIUtility.GetControlID("ButtonGrid".GetHashCode(), FocusType.Passive, buttonRect);
if (buttonIndex == selected)
selectedButtonID = id;
switch (Event.current.GetTypeForControl(id))
{
case EventType.MouseDown:
if (buttonRect.Contains(Event.current.mousePosition))
{
GUIUtility.hotControl = id;
Event.current.Use();
}
break;
case EventType.MouseDrag:
if (GUIUtility.hotControl == id)
Event.current.Use();
break;
case EventType.MouseUp:
if (GUIUtility.hotControl == id)
{
GUIUtility.hotControl = 0;
Event.current.Use();
GUI.changed = true;
return buttonIndex;
}
break;
case EventType.Repaint:
var buttonStyle = count == 1 ? style : (buttonIndex == 0 ? firstStyle : (buttonIndex == count - 1 ? lastStyle : midStyle));
var isSelected = selected == buttonIndex;
if (!isSelected)
{
GUI.DrawTexture(buttonRect, content.image, ScaleMode.ScaleToFit, true);
GUI.Label(new Rect(buttonRect.x, buttonRect.y, 32, 32), buttonIndex.ToString());
}
else
selectedButtonStyle = buttonStyle;
break;
}
GUI.enabled = wasEnabled;
}
// draw selected button at the end so it overflows nicer
if (selectedButtonStyle != null)
{
var buttonRect = buttonRects[selected];
var content = contents[selected];
var wasEnabled = GUI.enabled;
GUI.enabled &= (contentsEnabled == null || contentsEnabled[selected]);
GUI.DrawTexture(new Rect(buttonRect.x + 4, buttonRect.y + 4, buttonRect.width - 8, buttonRect.height - 8), content.image, ScaleMode.ScaleToFit, true);
DrawRectangleOutline(buttonRect, GUI.skin.settings.selectionColor);
GUI.Label(new Rect(buttonRect.x, buttonRect.y, 32, 32), selected.ToString());
GUI.enabled = wasEnabled;
}
return selected;
}
// Get Temp Texture Contents for Sprites.
private static GUIContent[] Temp(Texture[] images)
{
GUIContent[] retval = new GUIContent[images.Length];
for (int i = 0; i < images.Length; i++)
{
retval[i] = new GUIContent(images[i]);
}
return retval;
}
public Sprite GetActiveSprite()
{
if (m_SelectedSprite >= m_SpriteList.Length)
m_SelectedSprite = 0;
return m_SpriteList[m_SelectedSprite];
}
public bool ShowGUI(int selectedIndex)
{
bool repaint = false;
if (m_SpriteList == null || m_SpriteList.Length == 0)
return false;
int approxSize = 64;
int approxHolderSize = 66;
if (Styles.localGrid == null)
{
Styles.localGrid = new GUIStyle(Styles.gridList);
Styles.localGrid.fixedWidth = approxSize;
Styles.localGrid.fixedHeight = approxSize;
}
m_SelectedSprite = (selectedIndex > m_SpriteList.Length) ? 0 : selectedIndex;
EditorGUILayout.BeginHorizontal();
{
GUILayout.Label(Styles.spriteList, EditorStyles.label, GUILayout.Width(EditorGUIUtility.labelWidth - 5));
int cviewwidth = (int)(EditorGUIUtility.currentViewWidth - EditorGUIUtility.labelWidth - approxSize);
int columns = (int)(cviewwidth) / approxSize;
columns = columns == 0 ? 1 : columns;
int rows = (int)Mathf.Ceil((m_SpriteList.Length + columns - 1) / columns);
int lyColumns = (rows == 1) ? (approxHolderSize): (approxHolderSize * 2);
GUILayout.BeginVertical("box", new GUILayoutOption[] { GUILayout.Height(lyColumns) } );
{
m_ScrollPos = EditorGUILayout.BeginScrollView(m_ScrollPos, new GUILayoutOption[] { GUILayout.Height(lyColumns) });
int newBrush = SpriteSelectionGrid(m_SelectedSprite, m_SpriteList, approxSize, Styles.localGrid, Styles.missingSprites, columns, rows);
if (newBrush != m_SelectedSprite)
{
UpdateSelection(newBrush);
repaint = true;
}
EditorGUILayout.EndScrollView();
}
GUILayout.EndVertical();
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
return repaint;
}
int SpriteSelectionGrid(int selected, Sprite[] sprites, int approxSize, GUIStyle style, GUIContent emptyString, int columns, int rows)
{
int retval = 0;
if (sprites.Length != 0)
{
Rect r = GUILayoutUtility.GetRect((float)columns * approxSize, (float)rows * approxSize);
Event evt = Event.current;
if (evt.type == EventType.MouseDown && evt.clickCount == 2 && r.Contains(evt.mousePosition))
evt.Use();
m_Thumbnails = PreviewTexturesFromSprites(sprites);
retval = DoButtonGrid(r, selected, Temp(m_Thumbnails), null, (int)columns, style, style, style, style, GUI.ToolbarButtonSize.FitToContents);
}
else
GUILayout.Label(emptyString);
return retval;
}
internal static Texture[] PreviewTexturesFromSprites(Sprite[] sprites)
{
Texture[] retval = new Texture[sprites.Length];
for (int i = 0; i < sprites.Length; i++)
retval[i] = AssetPreview.GetAssetPreview(sprites[i]) ?? Texture2D.whiteTexture;
return retval;
}
}
} //namespace

View file

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

View file

@ -0,0 +1,168 @@
using System;
using System.Collections.Generic;
using UnityEngine.Analytics;
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.Events;
namespace UnityEditor.U2D
{
internal class SpriteShapeAnalyticsEvents
{
public class SpriteShapeEvent : UnityEvent<UnityEngine.U2D.SpriteShape> { }
public class SpriteShapeRendererEvent : UnityEvent<SpriteShapeRenderer> { }
private SpriteShapeEvent m_SpriteShape = new SpriteShapeEvent();
private SpriteShapeRendererEvent m_SpriteShapeRenderer = new SpriteShapeRendererEvent();
public virtual SpriteShapeEvent spriteShapeEvent { get { return m_SpriteShape; } }
public virtual SpriteShapeRendererEvent spriteShapeRendererEvent { get { return m_SpriteShapeRenderer; } }
}
[Serializable]
enum SpriteShapeAnalyticsEventType
{
SpriteShapeProfileCreated = 0,
SpriteShapeRendererCreated = 1
}
[Serializable]
struct SpriteShapeAnalyticsEvent
{
[SerializeField]
public SpriteShapeAnalyticsEventType sub_type;
[SerializeField]
public string data;
}
internal interface ISpriteShapeAnalyticsStorage
{
AnalyticsResult SendUsageEvent(SpriteShapeAnalyticsEvent evt);
void Dispose();
}
internal static class SpriteShapeAnalyticConstant
{
public const int k_MaxEventsPerHour = 1000;
public const int k_MaxNumberOfElements = 1000;
}
[Serializable]
internal class SpriteShapeAnalytics
{
const int k_SpriteShapeEventElementCount = 2;
ISpriteShapeAnalyticsStorage m_AnalyticsStorage;
[SerializeField]
SpriteShapeAnalyticsEvents m_EventBus = null;
internal SpriteShapeAnalyticsEvents eventBus
{
get
{
if (m_EventBus == null)
m_EventBus = new SpriteShapeAnalyticsEvents();
return m_EventBus;
}
}
public SpriteShapeAnalytics(ISpriteShapeAnalyticsStorage analyticsStorage)
{
m_AnalyticsStorage = analyticsStorage;
eventBus.spriteShapeEvent.AddListener(OnSpriteShapeCreated);
eventBus.spriteShapeRendererEvent.AddListener(OnSpriteShapeRendererCreated);
}
public void Dispose()
{
eventBus.spriteShapeEvent.RemoveListener(OnSpriteShapeCreated);
eventBus.spriteShapeRendererEvent.RemoveListener(OnSpriteShapeRendererCreated);
m_AnalyticsStorage.Dispose();
}
void OnSpriteShapeCreated(UnityEngine.U2D.SpriteShape shape)
{
SendUsageEvent(new SpriteShapeAnalyticsEvent()
{
sub_type = SpriteShapeAnalyticsEventType.SpriteShapeProfileCreated,
data = ""
});
}
void OnSpriteShapeRendererCreated(SpriteShapeRenderer renderer)
{
SendUsageEvent(new SpriteShapeAnalyticsEvent()
{
sub_type = SpriteShapeAnalyticsEventType.SpriteShapeRendererCreated,
data = ""
});
}
public void SendUsageEvent(SpriteShapeAnalyticsEvent evt)
{
m_AnalyticsStorage.SendUsageEvent(evt);
}
}
// For testing.
internal class SpriteShapeJsonAnalyticsStorage : ISpriteShapeAnalyticsStorage
{
[Serializable]
struct SpriteShapeToolEvents
{
[SerializeField]
public List<SpriteShapeAnalyticsEvent> events;
}
SpriteShapeToolEvents m_TotalEvents = new SpriteShapeToolEvents()
{
events = new List<SpriteShapeAnalyticsEvent>()
};
public AnalyticsResult SendUsageEvent(SpriteShapeAnalyticsEvent evt)
{
m_TotalEvents.events.Add(evt);
return AnalyticsResult.Ok;
}
public void Dispose()
{
try
{
string file = string.Format("analytics_{0}.json", System.DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss"));
if (System.IO.File.Exists(file))
System.IO.File.Delete(file);
System.IO.File.WriteAllText(file, JsonUtility.ToJson(m_TotalEvents, true));
}
catch (Exception ex)
{
Debug.Log(ex);
}
finally
{
m_TotalEvents.events.Clear();
}
}
}
[InitializeOnLoad]
internal class SpriteShapeUnityAnalyticsStorage : ISpriteShapeAnalyticsStorage
{
const string k_VendorKey = "unity.2d.spriteshape";
const int k_Version = 1;
public SpriteShapeUnityAnalyticsStorage()
{
EditorAnalytics.RegisterEventWithLimit("u2dSpriteShapeToolUsage", SpriteShapeAnalyticConstant.k_MaxEventsPerHour, SpriteShapeAnalyticConstant.k_MaxNumberOfElements, k_VendorKey, k_Version);
}
public AnalyticsResult SendUsageEvent(SpriteShapeAnalyticsEvent evt)
{
return EditorAnalytics.SendEventWithLimit("u2dSpriteShapeToolUsage", evt, k_Version);
}
public void Dispose() { }
}
}

View file

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

View file

@ -0,0 +1,25 @@
using UnityEngine;
using UnityEngine.U2D;
using UnityEditor;
namespace UnityEditor.U2D
{
public class SpriteShapeAssetPostProcessor : AssetPostprocessor
{
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
if (importedAssets.Length > 0)
{
GameObject[] allGOs = UnityEngine.Object.FindObjectsOfType<GameObject>();
foreach (GameObject go in allGOs)
{
if (!go.activeInHierarchy)
continue;
SpriteShapeController sc = go.GetComponent<SpriteShapeController>();
if (sc != null)
sc.RefreshSpriteShape();
}
}
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: b9102a9258b50f949a55f81945829f85
timeCreated: 1504669359
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,602 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.U2D;
using UnityEditor;
using UnityEditor.U2D.SpriteShapeInternal;
using UnityEditor.U2D.Common;
using UnityEditor.AnimatedValues;
using UnityEditor.U2D.Path;
using UnityEngine.SceneManagement;
namespace UnityEditor.U2D
{
[CustomEditor(typeof(SpriteShapeController))]
[CanEditMultipleObjects]
internal class SpriteShapeControllerEditor : PathComponentEditor<CustomPath>
{
private static class Contents
{
public static readonly GUIContent splineLabel = new GUIContent("Spline");
public static readonly string editSplineLabel = "Edit Spline";
public static readonly GUIContent fillLabel = new GUIContent("Fill");
public static readonly GUIContent colliderLabel = new GUIContent("Collider");
public static readonly GUIContent fillPixelPerUnitLabel = new GUIContent("Pixel Per Unit", "Pixel Per Unit for fill texture.");
public static readonly GUIContent spriteShapeProfile = new GUIContent("Profile", "The SpriteShape Profile to render");
public static readonly GUIContent materialLabel = new GUIContent("Material", "Material to be used by SpriteRenderer");
public static readonly GUIContent colorLabel = new GUIContent("Color", "Rendering color for the Sprite graphic");
public static readonly GUIContent metaDataLabel = new GUIContent("Meta Data", "SpriteShape specific controlpoint data");
public static readonly GUIContent showComponentsLabel = new GUIContent("Show Render Stuff", "Show Renderer Components.");
public static readonly GUIContent[] splineDetailOptions = { new GUIContent("High Quality"), new GUIContent("Medium Quality"), new GUIContent("Low Quality") };
public static readonly GUIContent splineDetail = new GUIContent("Detail", "Tessellation Quality for rendering.");
public static readonly GUIContent openEndedLabel = new GUIContent("Open Ended", "Is the path open ended or closed.");
public static readonly GUIContent adaptiveUVLabel = new GUIContent("Adaptive UV", "Allow Adaptive UV Generation");
public static readonly GUIContent enableTangentsLabel = new GUIContent("Enable Tangents", "Enable Tangents for 2D Lighting.");
public static readonly GUIContent worldUVLabel = new GUIContent("Worldspace UV", "Generate UV for world space.");
public static readonly GUIContent stretchUVLabel = new GUIContent("Stretch UV", "Stretch the Fill UV to full Rect.");
public static readonly GUIContent stretchTilingLabel = new GUIContent("Stretch Tiling", "Stretch Tiling Count.");
public static readonly GUIContent colliderDetail = new GUIContent("Detail", "Tessellation Quality on the collider.");
public static readonly GUIContent cornerThresholdDetail = new GUIContent("Corner Threshold", "Corner angle threshold below which corners wont be placed.");
public static readonly GUIContent colliderOffset = new GUIContent("Offset", "Extrude collider distance.");
public static readonly GUIContent updateColliderLabel = new GUIContent("Update Collider", "Update Collider as you edit SpriteShape");
public static readonly GUIContent optimizeColliderLabel = new GUIContent("Optimize Collider", "Cleanup planar self-intersections and optimize collider points");
public static readonly GUIContent optimizeGeometryLabel = new GUIContent("Optimize Geometry", "Simplify geometry");
public static readonly GUIContent cacheGeometryLabel = new GUIContent("Cache Geometry", "Bake geometry data. This will save geometry data on editor and load it on runtime instead of generating.");
}
private SerializedProperty m_SpriteShapeProp;
private SerializedProperty m_SplineDetailProp;
private SerializedProperty m_IsOpenEndedProp;
private SerializedProperty m_AdaptiveUVProp;
private SerializedProperty m_StretchUVProp;
private SerializedProperty m_StretchTilingProp;
private SerializedProperty m_WorldSpaceUVProp;
private SerializedProperty m_FillPixelPerUnitProp;
private SerializedProperty m_CornerAngleThresholdProp;
private SerializedProperty m_ColliderAutoUpdate;
private SerializedProperty m_ColliderDetailProp;
private SerializedProperty m_ColliderOffsetProp;
private SerializedProperty m_OptimizeColliderProp;
private SerializedProperty m_OptimizeGeometryProp;
private SerializedProperty m_EnableTangentsProp;
private SerializedProperty m_GeometryCachedProp;
private int m_CollidersCount = 0;
private int[] m_QualityValues = new int[] { (int)QualityDetail.High, (int)QualityDetail.Mid, (int)QualityDetail.Low };
readonly AnimBool m_ShowStretchOption = new AnimBool();
readonly AnimBool m_ShowNonStretchOption = new AnimBool();
private struct ShapeSegment
{
public int start;
public int end;
public int angleRange;
};
private struct ShapeAngleRange
{
public float start;
public float end;
public int order;
public int index;
};
int m_SelectedPoint = -1;
int m_SelectedAngleRange = -1;
int m_SpriteShapeHashCode = 0;
int m_SplineHashCode = 0;
List<ShapeSegment> m_ShapeSegments = new List<ShapeSegment>();
SpriteSelector spriteSelector = new SpriteSelector();
private SpriteShapeController m_SpriteShapeController
{
get { return target as SpriteShapeController; }
}
private void OnEnable()
{
if (target == null)
return;
m_SpriteShapeProp = serializedObject.FindProperty("m_SpriteShape");
m_SplineDetailProp = serializedObject.FindProperty("m_SplineDetail");
m_IsOpenEndedProp = serializedObject.FindProperty("m_Spline").FindPropertyRelative("m_IsOpenEnded");
m_AdaptiveUVProp = serializedObject.FindProperty("m_AdaptiveUV");
m_StretchUVProp = serializedObject.FindProperty("m_StretchUV");
m_StretchTilingProp = serializedObject.FindProperty("m_StretchTiling");
m_WorldSpaceUVProp = serializedObject.FindProperty("m_WorldSpaceUV");
m_FillPixelPerUnitProp = serializedObject.FindProperty("m_FillPixelPerUnit");
m_CornerAngleThresholdProp = serializedObject.FindProperty("m_CornerAngleThreshold");
m_ColliderAutoUpdate = serializedObject.FindProperty("m_UpdateCollider");
m_ColliderDetailProp = serializedObject.FindProperty("m_ColliderDetail");
m_ColliderOffsetProp = serializedObject.FindProperty("m_ColliderOffset");
m_OptimizeColliderProp = serializedObject.FindProperty("m_OptimizeCollider");
m_OptimizeGeometryProp = serializedObject.FindProperty("m_OptimizeGeometry");
m_EnableTangentsProp = serializedObject.FindProperty("m_EnableTangents");
m_GeometryCachedProp = serializedObject.FindProperty("m_GeometryCached");
m_ShowStretchOption.valueChanged.AddListener(Repaint);
m_ShowStretchOption.value = ShouldShowStretchOption();
m_ShowNonStretchOption.valueChanged.AddListener(Repaint);
m_ShowNonStretchOption.value = !ShouldShowStretchOption();
}
private bool OnCollidersAddedOrRemoved()
{
PolygonCollider2D polygonCollider = m_SpriteShapeController.polygonCollider;
EdgeCollider2D edgeCollider = m_SpriteShapeController.edgeCollider;
int collidersCount = 0;
if (polygonCollider != null)
collidersCount = collidersCount + 1;
if (edgeCollider != null)
collidersCount = collidersCount + 1;
if (collidersCount != m_CollidersCount)
{
m_CollidersCount = collidersCount;
return true;
}
return false;
}
public void DrawHeader(GUIContent content)
{
EditorGUILayout.LabelField(content, EditorStyles.boldLabel);
}
private bool ShouldShowStretchOption()
{
return m_StretchUVProp.boolValue;
}
static bool WithinRange(ShapeAngleRange angleRange, float inputAngle)
{
float range = angleRange.end - angleRange.start;
float angle = Mathf.Repeat(inputAngle - angleRange.start, 360f);
angle = (angle == 360.0f) ? 0 : angle;
return (angle >= 0f && angle <= range);
}
static int RangeFromAngle(List<ShapeAngleRange> angleRanges, float angle)
{
foreach (var range in angleRanges)
{
if (WithinRange(range, angle))
return range.index;
}
return -1;
}
private List<ShapeAngleRange> GetAngleRangeSorted(UnityEngine.U2D.SpriteShape ss)
{
List<ShapeAngleRange> angleRanges = new List<ShapeAngleRange>();
int i = 0;
foreach (var angleRange in ss.angleRanges)
{
ShapeAngleRange sar = new ShapeAngleRange() { start = angleRange.start, end = angleRange.end, order = angleRange.order, index = i };
angleRanges.Add(sar);
i++;
}
angleRanges.Sort((a, b) => a.order.CompareTo(b.order));
return angleRanges;
}
private void GenerateSegments(SpriteShapeController sc, List<ShapeAngleRange> angleRanges)
{
var controlPointCount = sc.spline.GetPointCount();
var angleRangeIndices = new int[controlPointCount];
ShapeSegment activeSegment = new ShapeSegment() { start = -1, end = -1, angleRange = -1 };
m_ShapeSegments.Clear();
for (int i = 0; i < controlPointCount; ++i)
{
var actv = i;
var next = SplineUtility.NextIndex(actv, controlPointCount);
var pos1 = sc.spline.GetPosition(actv);
var pos2 = sc.spline.GetPosition(next);
bool continueStrip = (sc.spline.GetTangentMode(actv) == ShapeTangentMode.Continuous), edgeUpdated = false;
float angle = 0;
if (false == continueStrip || activeSegment.start == -1)
angle = SplineUtility.SlopeAngle(pos1, pos2) + 90.0f;
next = (!sc.spline.isOpenEnded && next == 0) ? (actv + 1) : next;
int mn = (actv < next) ? actv : next;
int mx = (actv > next) ? actv : next;
var anglerange = RangeFromAngle(angleRanges, angle);
angleRangeIndices[actv] = anglerange;
if (anglerange == -1)
{
activeSegment = new ShapeSegment() { start = mn, end = mx, angleRange = anglerange };
m_ShapeSegments.Add(activeSegment);
continue;
}
// Check for Segments. Also check if the Segment Start has been resolved. Otherwise simply start with the next one
if (activeSegment.start != -1)
continueStrip = continueStrip && (angleRangeIndices[activeSegment.start] != -1);
bool canContinue = (actv != (controlPointCount - 1)) || (!sc.spline.isOpenEnded && (actv == (controlPointCount - 1)));
if (continueStrip && canContinue)
{
for (int s = 0; s < m_ShapeSegments.Count; ++s)
{
activeSegment = m_ShapeSegments[s];
if (activeSegment.start - mn == 1)
{
edgeUpdated = true;
activeSegment.start = mn;
m_ShapeSegments[s] = activeSegment;
break;
}
if (mx - activeSegment.end == 1)
{
edgeUpdated = true;
activeSegment.end = mx;
m_ShapeSegments[s] = activeSegment;
break;
}
}
}
if (!edgeUpdated)
{
activeSegment.start = mn;
activeSegment.end = mx;
activeSegment.angleRange = anglerange;
m_ShapeSegments.Add(activeSegment);
}
}
}
private int GetAngleRange(SpriteShapeController sc, int point, ref int startPoint)
{
int angleRange = -1;
startPoint = point;
for (int i = 0; i < m_ShapeSegments.Count; ++i)
{
if (point >= m_ShapeSegments[i].start && point < m_ShapeSegments[i].end)
{
angleRange = m_ShapeSegments[i].angleRange;
startPoint = point; // m_ShapeSegments[i].start;
if (angleRange >= sc.spriteShape.angleRanges.Count)
angleRange = 0;
break;
}
}
return angleRange;
}
private void UpdateSegments()
{
var sc = target as SpriteShapeController;
// Either SpriteShape Asset or SpriteShape Data has changed.
if (m_SpriteShapeHashCode != sc.spriteShapeHashCode || m_SplineHashCode != sc.splineHashCode)
{
List<ShapeAngleRange> angleRanges = GetAngleRangeSorted(sc.spriteShape);
GenerateSegments(sc, angleRanges);
m_SpriteShapeHashCode = sc.spriteShapeHashCode;
m_SplineHashCode = sc.splineHashCode;
m_SelectedPoint = -1;
}
}
private int ResolveSpriteIndex(List<int> spriteIndices, ISelection<int> selection, ref List<int> startPoints)
{
var spriteIndexValue = spriteIndices.FirstOrDefault();
var sc = target as SpriteShapeController;
var spline = sc.spline;
if (sc == null || sc.spriteShape == null)
return -1;
UpdateSegments();
if (sc.spriteShape != null)
{
if (selection.Count == 1)
{
m_SelectedAngleRange = GetAngleRange(sc, selection.elements[0], ref m_SelectedPoint);
startPoints.Add(m_SelectedPoint);
spriteIndexValue = spline.GetSpriteIndex(m_SelectedPoint);
}
else
{
m_SelectedAngleRange = -1;
foreach (var index in selection.elements)
{
int startPoint = index;
int angleRange = GetAngleRange(sc, index, ref startPoint);
if (m_SelectedAngleRange != -1 && angleRange != m_SelectedAngleRange)
{
m_SelectedAngleRange = -1;
break;
}
startPoints.Add(startPoint);
m_SelectedAngleRange = angleRange;
}
}
}
if (m_SelectedAngleRange != -1)
spriteSelector.UpdateSprites(sc.spriteShape.angleRanges[m_SelectedAngleRange].sprites.ToArray());
else
spriteIndexValue = -1;
return spriteIndexValue;
}
public int GetAngleRange(int index)
{
int startPoint = 0;
var sc = target as SpriteShapeController;
UpdateSegments();
return GetAngleRange(sc, index, ref startPoint);
}
public override void OnInspectorGUI()
{
var updateCollider = false;
EditorGUI.BeginChangeCheck();
serializedObject.Update();
EditorGUILayout.PropertyField(m_SpriteShapeProp, Contents.spriteShapeProfile);
var hasEditToolChanged = DoEditButtonChecked<SpriteShapeEditorTool>(PathEditorToolContents.icon, Contents.editSplineLabel);
if (hasEditToolChanged && !EditorTools.EditorTools.activeToolType.Equals(typeof(SpriteShapeEditorTool)))
SpriteShapeUpdateCache.UpdateCache(targets);
DoPathInspector<SpriteShapeEditorTool>();
var pathTool = SpriteShapeEditorTool.activeSpriteShapeEditorTool;
if (Selection.gameObjects.Length == 1 && pathTool != null)
{
var sc = target as SpriteShapeController;
var path = pathTool.GetPath(sc);
if (path != null)
{
var selection = path.selection;
if (selection.Count > 0)
{
var spline = sc.spline;
var spriteIndices = new List<int>();
List<int> startPoints = new List<int>();
foreach (int index in selection.elements)
spriteIndices.Add(spline.GetSpriteIndex(index));
var spriteIndexValue = ResolveSpriteIndex(spriteIndices, selection, ref startPoints);
if (spriteIndexValue != -1)
{
EditorGUI.BeginChangeCheck();
spriteSelector.ShowGUI(spriteIndexValue);
if (EditorGUI.EndChangeCheck())
{
foreach (var index in startPoints)
{
var data = path.GetData(index);
data.spriteIndex = spriteSelector.selectedIndex;
path.SetData(index, data);
}
pathTool.SetPath(target);
}
}
EditorGUILayout.Space();
}
}
}
DoSnappingInspector<SpriteShapeEditorTool>();
EditorGUILayout.Space();
DrawHeader(Contents.splineLabel);
EditorGUILayout.IntPopup(m_SplineDetailProp, Contents.splineDetailOptions, m_QualityValues, Contents.splineDetail);
serializedObject.ApplyModifiedProperties();
DoOpenEndedInspector<SpriteShapeEditorTool>(m_IsOpenEndedProp);
serializedObject.Update();
EditorGUILayout.PropertyField(m_AdaptiveUVProp, Contents.adaptiveUVLabel);
if (!m_IsOpenEndedProp.boolValue)
EditorGUILayout.PropertyField(m_OptimizeGeometryProp, Contents.optimizeGeometryLabel);
EditorGUILayout.PropertyField(m_EnableTangentsProp, Contents.enableTangentsLabel);
if (EditorTools.EditorTools.activeToolType == typeof(SpriteShapeEditorTool))
{
// Cache Geometry is only editable for Scene Objects or when in Prefab Isolation Mode.
if (Selection.gameObjects.Length == 1 && Selection.transforms.Contains(Selection.gameObjects[0].transform))
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_GeometryCachedProp, Contents.cacheGeometryLabel);
if (EditorGUI.EndChangeCheck())
{
if (m_GeometryCachedProp.boolValue)
{
var geometryCache = m_SpriteShapeController.spriteShapeGeometryCache;
if (!geometryCache)
geometryCache = m_SpriteShapeController.gameObject
.AddComponent<SpriteShapeGeometryCache>();
geometryCache.hideFlags = HideFlags.HideInInspector;
}
else
{
if (m_SpriteShapeController.spriteShapeGeometryCache)
Object.DestroyImmediate(m_SpriteShapeController.spriteShapeGeometryCache);
}
m_SpriteShapeController.RefreshSpriteShape();
}
}
SpriteShapeUpdateCache.s_cacheGeometrySet = true;
}
EditorGUI.BeginChangeCheck();
var threshold = EditorGUILayout.Slider(Contents.cornerThresholdDetail, m_CornerAngleThresholdProp.floatValue, 0.0f, 90.0f);
if (EditorGUI.EndChangeCheck())
{
m_CornerAngleThresholdProp.floatValue = threshold;
updateCollider = true;
}
EditorGUILayout.Space();
DrawHeader(Contents.fillLabel);
EditorGUILayout.PropertyField(m_StretchUVProp, Contents.stretchUVLabel);
if (ShouldShowStretchOption())
{
EditorGUILayout.PropertyField(m_StretchTilingProp, Contents.stretchTilingLabel);
}
else
{
EditorGUILayout.PropertyField(m_FillPixelPerUnitProp, Contents.fillPixelPerUnitLabel);
EditorGUILayout.PropertyField(m_WorldSpaceUVProp, Contents.worldUVLabel);
}
if (m_SpriteShapeController.gameObject.GetComponent<PolygonCollider2D>() != null || m_SpriteShapeController.gameObject.GetComponent<EdgeCollider2D>() != null)
{
EditorGUILayout.Space();
DrawHeader(Contents.colliderLabel);
EditorGUILayout.PropertyField(m_ColliderAutoUpdate, Contents.updateColliderLabel);
if (m_ColliderAutoUpdate.boolValue)
{
EditorGUILayout.PropertyField(m_ColliderOffsetProp, Contents.colliderOffset);
EditorGUILayout.PropertyField(m_OptimizeColliderProp, Contents.optimizeColliderLabel);
if (m_OptimizeColliderProp.boolValue)
EditorGUILayout.IntPopup(m_ColliderDetailProp, Contents.splineDetailOptions, m_QualityValues, Contents.colliderDetail);
}
}
if (EditorGUI.EndChangeCheck())
{
updateCollider = true;
}
serializedObject.ApplyModifiedProperties();
if (updateCollider || OnCollidersAddedOrRemoved())
BakeCollider();
}
void BakeCollider()
{
if (m_SpriteShapeController.autoUpdateCollider == false)
return;
PolygonCollider2D polygonCollider = m_SpriteShapeController.polygonCollider;
if (polygonCollider)
{
Undo.RegisterCompleteObjectUndo(polygonCollider, Undo.GetCurrentGroupName());
EditorUtility.SetDirty(polygonCollider);
m_SpriteShapeController.RefreshSpriteShape();
}
EdgeCollider2D edgeCollider = m_SpriteShapeController.edgeCollider;
if (edgeCollider)
{
Undo.RegisterCompleteObjectUndo(edgeCollider, Undo.GetCurrentGroupName());
EditorUtility.SetDirty(edgeCollider);
m_SpriteShapeController.RefreshSpriteShape();
}
}
void ShowMaterials(bool show)
{
HideFlags hideFlags = HideFlags.HideInInspector;
if (show)
hideFlags = HideFlags.None;
Material[] materials = m_SpriteShapeController.spriteShapeRenderer.sharedMaterials;
foreach (Material material in materials)
{
material.hideFlags = hideFlags;
EditorUtility.SetDirty(material);
}
}
[DrawGizmo(GizmoType.InSelectionHierarchy)]
static void RenderSpline(SpriteShapeController m_SpriteShapeController, GizmoType gizmoType)
{
if (EditorTools.EditorTools.activeToolType == typeof(SpriteShapeEditorTool))
return;
var m_Spline = m_SpriteShapeController.spline;
var oldMatrix = Handles.matrix;
var oldColor = Handles.color;
Handles.matrix = m_SpriteShapeController.transform.localToWorldMatrix;
Handles.color = Color.grey;
var pointCount = m_Spline.GetPointCount();
for (var i = 0; i < (m_Spline.isOpenEnded ? pointCount - 1 : pointCount); ++i)
{
Vector3 p1 = m_Spline.GetPosition(i);
Vector3 p2 = m_Spline.GetPosition((i + 1) % pointCount);
var t1 = p1 + m_Spline.GetRightTangent(i);
var t2 = p2 + m_Spline.GetLeftTangent((i + 1) % pointCount);
Vector3[] bezierPoints = Handles.MakeBezierPoints(p1, p2, t1, t2, m_SpriteShapeController.splineDetail);
Handles.DrawAAPolyLine(bezierPoints);
}
Handles.matrix = oldMatrix;
Handles.color = oldColor;
}
}
[UnityEditor.InitializeOnLoad]
internal static class SpriteShapeUpdateCache
{
internal static bool s_cacheGeometrySet = false;
static SpriteShapeUpdateCache()
{
UnityEditor.EditorApplication.playModeStateChanged += change =>
{
if (change == UnityEditor.PlayModeStateChange.ExitingEditMode)
UpdateSpriteShapeCacheInOpenScenes();
};
}
static void UpdateSpriteShapeCacheInOpenScenes()
{
for (int i = 0; s_cacheGeometrySet && (i < SceneManager.sceneCount); ++i)
{
var scene = SceneManager.GetSceneAt(i);
var gos = scene.GetRootGameObjects();
foreach (var go in gos)
{
var scs = go.GetComponentsInChildren<SpriteShapeController>();
foreach (var sc in scs)
if (sc.spriteShapeGeometryCache)
sc.spriteShapeGeometryCache.UpdateGeometryCache();
}
}
s_cacheGeometrySet = false;
}
internal static void UpdateCache(UnityEngine.Object[] targets)
{
foreach (var t in targets)
{
var s = t as SpriteShapeController;
if (s)
if (s.spriteShapeGeometryCache)
s.spriteShapeGeometryCache.UpdateGeometryCache();
}
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 8dad9bd3cf16d46f794821e888c403c2
timeCreated: 1503819723
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,654 @@
using UnityEngine;
using UnityEngine.U2D;
using UnityEditor;
using UnityEditor.AnimatedValues;
using UnityEditorInternal;
using UnityEditor.U2D.Common;
using System.Collections.Generic;
using UnityEditor.U2D.SpriteShape;
namespace UnityEditor.U2D
{
[CustomEditor(typeof(UnityEngine.U2D.SpriteShape)), CanEditMultipleObjects]
public class SpriteShapeEditor : Editor, IAngleRangeCache
{
private static class Contents
{
public static readonly GUIContent fillTextureLabel = new GUIContent("Texture", "Fill texture used for Shape Fill.");
public static readonly GUIContent fillScaleLabel = new GUIContent("Offset", "Determines Border Offset for Shape.");
public static readonly GUIContent useSpriteBorderLabel = new GUIContent("Use Sprite Borders", "Draw Sprite Borders on discontinuities");
public static readonly GUIContent cornerTypeLabel = new GUIContent("Corner Type", "Corner type sprite used.");
public static readonly GUIContent controlPointsLabel = new GUIContent("Control Points");
public static readonly GUIContent fillLabel = new GUIContent("Fill");
public static readonly GUIContent cornerLabel = new GUIContent("Corners");
public static readonly GUIContent cornerListLabel = new GUIContent("Corner List");
public static readonly GUIContent cornerSpriteTypeLabel = new GUIContent("Corner Sprite");
public static readonly GUIContent angleRangesLabel = new GUIContent("Angle Ranges");
public static readonly GUIContent spritesLabel = new GUIContent("Sprites");
public static readonly GUIContent angleRangeLabel = new GUIContent("Angle Range ({0})");
public static readonly GUIContent wrapModeErrorLabel = new GUIContent("Fill texture must have wrap modes set to Repeat. Please re-import.");
public static readonly Color proBackgroundColor = new Color32(49, 77, 121, 255);
public static readonly Color proBackgroundRangeColor = new Color32(25, 25, 25, 128);
public static readonly Color proColor1 = new Color32(10, 46, 42, 255);
public static readonly Color proColor2 = new Color32(33, 151, 138, 255);
public static readonly Color defaultColor1 = new Color32(25, 61, 57, 255);
public static readonly Color defaultColor2 = new Color32(47, 166, 153, 255);
public static readonly Color defaultBackgroundColor = new Color32(64, 92, 136, 255);
}
private SerializedProperty m_FillTextureProp;
private SerializedProperty m_AngleRangesProp;
private SerializedProperty m_CornerSpritesProp;
private SerializedProperty m_FillOffsetProp;
private SerializedProperty m_UseSpriteBordersProp;
private ReorderableList m_AngleRangeSpriteList = null;
private ReorderableList m_EmptySpriteList = null;
[SerializeField]
private float m_PreviewAngle = 0f;
[SerializeField]
private int m_SelectedIndex;
private const int kInvalidMinimum = -1;
private Rect m_AngleRangeRect;
private AngleRangeController controller;
private AngleRange m_CurrentAngleRange;
private Dictionary<int, int> m_SpriteSelection = new Dictionary<int, int>();
private Sprite m_PreviewSprite;
private Mesh m_PreviewSpriteMesh;
private Mesh previewSpriteMesh
{
get
{
if (m_PreviewSpriteMesh == null)
{
m_PreviewSpriteMesh = new Mesh();
m_PreviewSpriteMesh.MarkDynamic();
m_PreviewSpriteMesh.hideFlags = HideFlags.DontSave;
}
return m_PreviewSpriteMesh;
}
}
public List<AngleRange> angleRanges
{
get
{
if (spriteShape == null)
return new List<AngleRange>();
Debug.Assert(spriteShape != null);
return spriteShape.angleRanges;
}
}
public int selectedIndex
{
get { return m_SelectedIndex; }
set { m_SelectedIndex = value; }
}
bool isSelectedIndexValid
{
get { return (selectedIndex != kInvalidMinimum && selectedIndex < angleRanges.Count); }
}
public float previewAngle
{
get { return m_PreviewAngle; }
set
{
m_PreviewAngle = value;
SessionState.SetFloat("SpriteShape/PreviewAngle/" + target.GetInstanceID(), value);
}
}
public UnityEngine.U2D.SpriteShape spriteShape
{
get
{
if (target == null)
return null;
return target as UnityEngine.U2D.SpriteShape;
}
}
public void RegisterUndo(string name)
{
Undo.RegisterCompleteObjectUndo(spriteShape, name);
Undo.RegisterCompleteObjectUndo(this, name);
EditorUtility.SetDirty(spriteShape);
}
public void OnEnable()
{
if (target == null)
return;
m_PreviewAngle = SessionState.GetFloat("SpriteShape/PreviewAngle/" + target.GetInstanceID(), m_PreviewAngle);
m_FillTextureProp = this.serializedObject.FindProperty("m_FillTexture");
m_UseSpriteBordersProp = serializedObject.FindProperty("m_UseSpriteBorders");
m_AngleRangesProp = this.serializedObject.FindProperty("m_Angles");
m_CornerSpritesProp = this.serializedObject.FindProperty("m_CornerSprites");
m_FillOffsetProp = this.serializedObject.FindProperty("m_FillOffset");
selectedIndex = SpriteShapeEditorUtility.GetRangeIndexFromAngle(angleRanges, m_PreviewAngle);
SetupAngleRangeController();
Undo.undoRedoPerformed += UndoRedoPerformed;
}
public override bool RequiresConstantRepaint()
{
return true;
}
private void SetupAngleRangeController()
{
var radius = 125f;
var angleOffset = -90f;
var color1 = Contents.defaultColor1;
var color2 = Contents.defaultColor2;
if (!EditorGUIUtility.isProSkin)
{
color1 = Contents.proColor1;
color2 = Contents.proColor2;
}
controller = new AngleRangeController();
controller.view = new AngleRangeView();
controller.cache = this;
controller.radius = radius;
controller.angleOffset = angleOffset;
controller.gradientMin = color1;
controller.gradientMid = color2;
controller.gradientMax = color1;
controller.snap = true;
controller.selectionChanged += OnSelectionChange;
OnSelectionChange();
}
private void OnSelectionChange()
{
CreateReorderableSpriteList();
EditorApplication.delayCall += () =>
{
m_CurrentAngleRange = controller.selectedAngleRange;
};
}
private void OnDestroy()
{
if (m_PreviewSpriteMesh)
Object.DestroyImmediate(m_PreviewSpriteMesh);
Undo.undoRedoPerformed -= UndoRedoPerformed;
}
private void UndoRedoPerformed()
{
OnSelectionChange();
}
private void OnSelelectSpriteCallback(ReorderableList list)
{
if (selectedIndex >= 0)
{
SetPreviewSpriteIndex(selectedIndex, list.index);
}
}
private bool OnCanAddCallback(ReorderableList list)
{
return (list.count < 64);
}
private void OnRemoveSprite(ReorderableList list)
{
var count = list.count;
var index = list.index;
ReorderableList.defaultBehaviours.DoRemoveButton(list);
if (list.count < count && list.count > 0)
{
list.index = Mathf.Clamp(index, 0, list.count - 1);
OnSelelectSpriteCallback(list);
}
}
private void DrawSpriteListHeader(Rect rect)
{
EditorGUI.LabelField(rect, Contents.spritesLabel);
HandleAngleSpriteListGUI(rect);
}
private void DrawSpriteListElement(Rect rect, int index, bool selected, bool focused)
{
rect.y += 2f;
rect.height = EditorGUIUtility.singleLineHeight;
var sprite = m_AngleRangesProp.GetArrayElementAtIndex(selectedIndex).FindPropertyRelative("m_Sprites").GetArrayElementAtIndex(index);
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(rect, sprite, GUIContent.none);
if (EditorGUI.EndChangeCheck())
{
m_AngleRangeSpriteList.index = index;
OnSelelectSpriteCallback(m_AngleRangeSpriteList);
}
}
public void DrawHeader(GUIContent content)
{
EditorGUILayout.LabelField(content, EditorStyles.boldLabel);
}
private void SetPreviewSpriteIndex(int rangeIndex, int index)
{
m_SpriteSelection[rangeIndex] = index;
}
private int GetPreviewSpriteIndex(int rangeIndex)
{
int index;
m_SpriteSelection.TryGetValue(rangeIndex, out index);
return index;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.Space();
DrawHeader(Contents.controlPointsLabel);
EditorGUILayout.PropertyField(m_UseSpriteBordersProp, Contents.useSpriteBorderLabel);
EditorGUILayout.Space();
DrawHeader(Contents.fillLabel);
EditorGUILayout.PropertyField(m_FillTextureProp, Contents.fillTextureLabel);
EditorGUILayout.Slider(m_FillOffsetProp, -0.5f, 0.5f, Contents.fillScaleLabel);
if (m_FillTextureProp.objectReferenceValue != null)
{
var fillTex = m_FillTextureProp.objectReferenceValue as Texture2D;
if (fillTex.wrapModeU != TextureWrapMode.Repeat || fillTex.wrapModeV != TextureWrapMode.Repeat)
EditorGUILayout.HelpBox(Contents.wrapModeErrorLabel.text, MessageType.Warning);
}
EditorGUILayout.Space();
DrawHeader(Contents.angleRangesLabel);
DoRangesGUI();
if (targets.Length == 1)
{
DoRangeInspector();
DoCreateRangeButton();
}
EditorGUILayout.Space();
DrawHeader(Contents.cornerLabel);
HashSet<Sprite> tightMeshSprites = new HashSet<Sprite>();
for (int i = 0; i < angleRanges.Count; ++i)
{
AngleRange angleRange = angleRanges[i];
foreach (Sprite sprite in angleRange.sprites)
{
if (sprite != null)
{
string assetPath = AssetDatabase.GetAssetPath(sprite);
TextureImporter importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
if (importer != null)
{
TextureImporterSettings textureSettings = new TextureImporterSettings();
importer.ReadTextureSettings(textureSettings);
if (textureSettings.spriteMeshType == SpriteMeshType.Tight)
tightMeshSprites.Add(sprite);
}
}
}
}
EditorGUIUtility.labelWidth = EditorGUIUtility.labelWidth + 20f;
for (int i = 0; i < m_CornerSpritesProp.arraySize; ++i)
{
var m_CornerProp = m_CornerSpritesProp.GetArrayElementAtIndex(i);
var m_CornerType = m_CornerProp.FindPropertyRelative("m_CornerType");
var m_CornerSprite = m_CornerProp.FindPropertyRelative("m_Sprites").GetArrayElementAtIndex(0);
EditorGUILayout.PropertyField(m_CornerSprite, new GUIContent(m_CornerType.enumDisplayNames[m_CornerType.intValue]));
var sprite = m_CornerSprite.objectReferenceValue as Sprite;
if (sprite != null)
{
string assetPath = AssetDatabase.GetAssetPath(sprite);
TextureImporter importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
if (importer != null)
{
TextureImporterSettings textureSettings = new TextureImporterSettings();
importer.ReadTextureSettings(textureSettings);
if (textureSettings.spriteMeshType == SpriteMeshType.Tight)
tightMeshSprites.Add(sprite);
}
}
}
EditorGUIUtility.labelWidth = 0;
serializedObject.ApplyModifiedProperties();
if (tightMeshSprites.Count > 0)
{
int i = 0;
string tightSpriteWarning = "The following sprites ( ";
foreach (var sprite in tightMeshSprites)
{
string appendString = (i < tightMeshSprites.Count - 1) ? ", " : " ) ";
tightSpriteWarning += (sprite.name + appendString);
++i;
}
tightSpriteWarning += "are imported as Sprites using Tight mesh. This can lead to Rendering Artifacts. Please use Full Rect.";
EditorGUILayout.HelpBox(tightSpriteWarning, MessageType.Warning);
}
controller.view.DoCreateRangeTooltip();
}
private void DoRangeInspector()
{
var start = 0f;
var end = 0f;
var order = 0;
if (m_CurrentAngleRange != null)
{
start = m_CurrentAngleRange.start;
end = m_CurrentAngleRange.end;
order = m_CurrentAngleRange.order;
}
using (new EditorGUI.DisabledGroupScope(m_CurrentAngleRange == null))
{
DrawHeader(new GUIContent(string.Format(Contents.angleRangeLabel.text, (end - start))));
EditorGUIUtility.labelWidth = 0f;
EditorGUI.BeginChangeCheck();
RangeField(ref start, ref end, ref order);
if (EditorGUI.EndChangeCheck() && m_CurrentAngleRange != null)
{
RegisterUndo("Set Range");
m_CurrentAngleRange.order = order;
controller.SetRange(m_CurrentAngleRange, start, end);
if (start >= end)
controller.RemoveInvalidRanges();
}
EditorGUILayout.Space();
if (m_AngleRangeSpriteList != null && angleRanges.Count > 0)
m_AngleRangeSpriteList.DoLayoutList();
else
m_EmptySpriteList.DoLayoutList();
}
}
private void DoCreateRangeButton()
{
if (selectedIndex != kInvalidMinimum && angleRanges.Count != 0)
return;
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Create Range", GUILayout.MaxWidth(100f)))
{
RegisterUndo("Create Range");
controller.CreateRange();
}
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
}
private void RangeField(ref float start, ref float end, ref int order)
{
var values = new int[] { Mathf.RoundToInt(-start), Mathf.RoundToInt(-end), order };
var labels = new GUIContent[] { new GUIContent("Start"), new GUIContent("End"), new GUIContent("Order") };
var position = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
EditorGUI.BeginChangeCheck();
SpriteShapeEditorGUI.MultiDelayedIntField(position, labels, values, 40f);
if (EditorGUI.EndChangeCheck())
{
start = -1f * values[0];
end = -1f * values[1];
order = values[2];
}
}
private void HandleAngleSpriteListGUI(Rect rect)
{
if (m_CurrentAngleRange == null || !isSelectedIndexValid)
return;
var currentEvent = Event.current;
var usedEvent = false;
var sprites = m_AngleRangesProp.GetArrayElementAtIndex(selectedIndex).FindPropertyRelative("m_Sprites");
switch (currentEvent.type)
{
case EventType.DragExited:
if (GUI.enabled)
HandleUtility.Repaint();
break;
case EventType.DragUpdated:
case EventType.DragPerform:
if (rect.Contains(currentEvent.mousePosition) && GUI.enabled)
{
// Check each single object, so we can add multiple objects in a single drag.
var didAcceptDrag = false;
var references = DragAndDrop.objectReferences;
foreach (var obj in references)
{
if (obj is Sprite)
{
Sprite spr = obj as Sprite;
if (spr.texture != null)
{
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
if (currentEvent.type == EventType.DragPerform && sprites.arraySize < 64)
{
sprites.InsertArrayElementAtIndex(sprites.arraySize);
var spriteProp = sprites.GetArrayElementAtIndex(sprites.arraySize - 1);
spriteProp.objectReferenceValue = obj;
didAcceptDrag = true;
DragAndDrop.activeControlID = 0;
}
}
}
}
serializedObject.ApplyModifiedProperties();
if (didAcceptDrag)
{
GUI.changed = true;
DragAndDrop.AcceptDrag();
usedEvent = true;
}
}
break;
}
if (usedEvent)
currentEvent.Use();
}
private void DoRangesGUI()
{
var radius = controller.radius;
EditorGUILayout.Space();
EditorGUILayout.Space();
var rect = EditorGUILayout.GetControlRect(false, radius * 2f);
if (Event.current.type == EventType.Repaint)
m_AngleRangeRect = rect;
{ //Draw background
var backgroundColor = Contents.proBackgroundColor;
var backgroundRangeColor = Contents.proBackgroundRangeColor;
if (!EditorGUIUtility.isProSkin)
{
backgroundColor = Contents.defaultBackgroundColor;
backgroundRangeColor.a = 0.1f;
}
var c = Handles.color;
Handles.color = backgroundRangeColor;
SpriteShapeHandleUtility.DrawSolidArc(rect.center, Vector3.forward, Vector3.right, 360f, radius, AngleRangeGUI.kRangeWidth);
Handles.color = backgroundColor;
Handles.DrawSolidDisc(rect.center, Vector3.forward, radius - AngleRangeGUI.kRangeWidth + 1f);
Handles.color = c;
}
if (targets.Length == 1)
{
{ //Draw fill texture and sprite preview
SpriteShapeHandleUtility.DrawTextureArc(
m_FillTextureProp.objectReferenceValue as Texture, 100.0f,
rect.center, Vector3.forward, Quaternion.AngleAxis(m_PreviewAngle, Vector3.forward) * Vector3.right, 180f,
radius - AngleRangeGUI.kRangeWidth);
var rectSize = Vector2.one * (radius - AngleRangeGUI.kRangeWidth) * 2f;
rectSize.y *= 0.33f;
var spriteRect = new Rect(rect.center - rectSize * 0.5f, rectSize);
DrawSpritePreview(spriteRect);
HandleSpritePreviewCycle(spriteRect);
}
controller.rect = m_AngleRangeRect;
controller.OnGUI();
}
EditorGUILayout.Space();
EditorGUILayout.Space();
}
private void CreateReorderableSpriteList()
{
if (m_EmptySpriteList == null)
{
m_EmptySpriteList = new ReorderableList(new List<Sprite>(), typeof(Sprite), false, true, false, false)
{
drawHeaderCallback = (Rect rect) => { EditorGUI.LabelField(rect, Contents.spritesLabel); }
};
}
m_AngleRangeSpriteList = null;
serializedObject.UpdateIfRequiredOrScript();
Debug.Assert(angleRanges.Count == m_AngleRangesProp.arraySize);
Debug.Assert(selectedIndex < angleRanges.Count);
if (targets.Length == 1 && isSelectedIndexValid)
{
var spritesProp = m_AngleRangesProp.GetArrayElementAtIndex(selectedIndex).FindPropertyRelative("m_Sprites");
m_AngleRangeSpriteList = new ReorderableList(spritesProp.serializedObject, spritesProp)
{
drawElementCallback = DrawSpriteListElement,
drawHeaderCallback = DrawSpriteListHeader,
onSelectCallback = OnSelelectSpriteCallback,
onRemoveCallback = OnRemoveSprite,
onCanAddCallback = OnCanAddCallback,
elementHeight = EditorGUIUtility.singleLineHeight + 6f
};
}
}
private void DrawSpritePreview(Rect rect)
{
if (Event.current.type != EventType.Repaint)
return;
if (!isSelectedIndexValid)
return;
var sprites = angleRanges[selectedIndex].sprites;
if (sprites.Count == 0)
return;
var selectedSpriteIndex = GetPreviewSpriteIndex(selectedIndex);
if (selectedSpriteIndex == kInvalidMinimum || selectedSpriteIndex >= sprites.Count)
return;
var sprite = sprites[selectedSpriteIndex];
if (sprite == null)
return;
if (m_PreviewSprite != sprite)
{
m_PreviewSprite = sprite;
EditorSpriteGUIUtility.DrawSpriteInRectPrepare(rect, sprite, EditorSpriteGUIUtility.FitMode.Tiled, true, true, previewSpriteMesh);
}
var material = EditorSpriteGUIUtility.spriteMaterial;
material.mainTexture = EditorSpriteGUIUtility.GetOriginalSpriteTexture(sprite);
EditorSpriteGUIUtility.DrawMesh(previewSpriteMesh, material, rect.center, Quaternion.AngleAxis(m_PreviewAngle, Vector3.forward), new Vector3(1f, -1f, 1f));
}
private void HandleSpritePreviewCycle(Rect rect)
{
if (!isSelectedIndexValid)
return;
Debug.Assert(m_AngleRangeSpriteList != null);
var spriteIndex = GetPreviewSpriteIndex(selectedIndex);
var sprites = angleRanges[selectedIndex].sprites;
var ev = Event.current;
if (ev.type == EventType.MouseDown && ev.button == 0 && HandleUtility.nearestControl == 0 &&
ContainsPosition(rect, ev.mousePosition, m_PreviewAngle) && spriteIndex != kInvalidMinimum && sprites.Count > 0)
{
spriteIndex = Mathf.RoundToInt(Mathf.Repeat(spriteIndex + 1f, sprites.Count));
SetPreviewSpriteIndex(selectedIndex, spriteIndex);
m_AngleRangeSpriteList.GrabKeyboardFocus();
m_AngleRangeSpriteList.index = spriteIndex;
ev.Use();
}
}
private bool ContainsPosition(Rect rect, Vector2 position, float angle)
{
Vector2 delta = position - rect.center;
position = (Vector2)(Quaternion.AngleAxis(-angle, Vector3.forward) * (Vector3)delta) + rect.center;
return rect.Contains(position);
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 1e5643f1bcfd748dbb9155663dddd82b
timeCreated: 1503758178
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,29 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
using UnityEditor;
namespace UnityEditor.U2D
{
internal class SpriteShapeEditorAnalytics : ScriptableSingleton<SpriteShapeEditorAnalytics>
{
SpriteShapeAnalytics m_Analytics = null;
internal SpriteShapeAnalyticsEvents eventBus
{
get { return analytics.eventBus; }
}
private SpriteShapeAnalytics analytics
{
get
{
if (m_Analytics == null)
m_Analytics = new SpriteShapeAnalytics(new SpriteShapeUnityAnalyticsStorage());
return m_Analytics;
}
}
}
}

View file

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

View file

@ -0,0 +1,36 @@
using UnityEditor;
using UnityEngine;
using UnityEditor.Sprites;
using System.Collections;
using System.Collections.Generic;
namespace UnityEditor.U2D
{
public class SpriteShapeEditorGUI
{
private const float kSpacingSubLabel = 2.0f;
private const float kMiniLabelW = 13;
private const int kVerticalSpacingMultiField = 0;
private const float kIndentPerLevel = 15;
public static int s_FoldoutHash = "Foldout".GetHashCode();
public static void MultiDelayedIntField(Rect position, GUIContent[] subLabels, int[] values, float labelWidth)
{
int eCount = values.Length;
float w = (position.width - (eCount - 1) * kSpacingSubLabel) / eCount;
Rect nr = new Rect(position);
nr.width = w;
float t = EditorGUIUtility.labelWidth;
int l = EditorGUI.indentLevel;
EditorGUIUtility.labelWidth = labelWidth;
EditorGUI.indentLevel = 0;
for (int i = 0; i < values.Length; i++)
{
values[i] = EditorGUI.DelayedIntField(nr, subLabels[i], values[i]);
nr.x += w + kSpacingSubLabel;
}
EditorGUIUtility.labelWidth = t;
EditorGUI.indentLevel = l;
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 201daa6b3b251405cba71fba2e47ac69
timeCreated: 1503758178
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,316 @@
using System;
using UnityEngine;
using UnityEngine.U2D;
using UnityEditor;
using UnityEditor.U2D.Path;
using UnityEditor.EditorTools;
using UnityEditor.ShortcutManagement;
using UnityEditor.U2D.Common;
namespace UnityEditor.U2D.SpriteShapeInternal
{
internal class CustomDrawer : IDrawer
{
private IDrawer m_Drawer = new Drawer();
private SpriteShapeController m_SpriteShapeController;
public CustomDrawer(SpriteShapeController spriteShapeController)
{
m_SpriteShapeController = spriteShapeController;
}
private int GetSubDivisionCount()
{
return m_SpriteShapeController.splineDetail;
}
void IDrawer.DrawBezier(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4, float width, Color color)
{
Handles.color = color;
Handles.DrawAAPolyLine(null, width, Handles.MakeBezierPoints(p1, p4, p2, p3, GetSubDivisionCount()));
}
void IDrawer.DrawCreatePointPreview(Vector3 position)
{
m_Drawer.DrawCreatePointPreview(position);
}
void IDrawer.DrawLine(Vector3 p1, Vector3 p2, float width, Color color)
{
m_Drawer.DrawLine(p1, p2, width, color);
}
void IDrawer.DrawPoint(Vector3 position)
{
m_Drawer.DrawPoint(position);
}
void IDrawer.DrawPointHovered(Vector3 position)
{
m_Drawer.DrawPointHovered(position);
}
void IDrawer.DrawPointSelected(Vector3 position)
{
m_Drawer.DrawPointSelected(position);
}
void IDrawer.DrawTangent(Vector3 position, Vector3 tangent)
{
m_Drawer.DrawTangent(position, tangent);
}
}
[Serializable]
internal class SpriteShapeData
{
public float height = 1f;
public int spriteIndex;
public bool corner = true;
}
internal class ScriptableSpriteShapeData : ScriptableData<SpriteShapeData> { }
[CanEditMultipleObjects]
[CustomEditor(typeof(ScriptableSpriteShapeData))]
internal class SpriteShapeDataInspector : Editor
{
private static class Contents
{
public static readonly GUIContent heightLabel = new GUIContent("Height", "Height override for control point.");
public static readonly GUIContent spriteIndexLabel = new GUIContent("Sprite Variant", "Index of the sprite variant at this control point");
public static readonly GUIContent invalidSpriteLabel = new GUIContent("No sprite defined");
public static readonly GUIContent cornerLabel = new GUIContent("Corner", "Set if Corner is automatic or disabled.");
public static readonly int[] cornerValues = { 0, 1 };
public static readonly GUIContent[] cornerOptions = { new GUIContent("Disabled"), new GUIContent("Automatic") };
}
private SerializedProperty m_Data;
private SerializedProperty m_SpriteIndexProperty;
private SerializedProperty m_HeightProperty;
private SerializedProperty m_CornerProperty;
private void OnEnable()
{
m_Data = serializedObject.FindProperty("m_Data");
m_SpriteIndexProperty = m_Data.FindPropertyRelative("spriteIndex");
m_HeightProperty = m_Data.FindPropertyRelative("height");
m_CornerProperty = m_Data.FindPropertyRelative("corner");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUI.BeginChangeCheck();
var heightValue = EditorGUILayout.Slider(Contents.heightLabel, m_HeightProperty.floatValue, 0.1f, 4.0f);
if (EditorGUI.EndChangeCheck())
m_HeightProperty.floatValue = heightValue;
EditorGUI.BeginChangeCheck();
var cornerValue = EditorGUILayout.IntPopup(Contents.cornerLabel, m_CornerProperty.boolValue ? 1 : 0, Contents.cornerOptions, Contents.cornerValues) > 0;
if (EditorGUI.EndChangeCheck())
m_CornerProperty.boolValue = cornerValue;
serializedObject.ApplyModifiedProperties();
}
}
internal class CustomPath : GenericScriptablePath<SpriteShapeData> { }
[CanEditMultipleObjects]
[CustomEditor(typeof(CustomPath))]
internal class CustomPathInspector : GenericScriptablePathInspector<ScriptableSpriteShapeData, SpriteShapeData> { }
[EditorTool("Edit SpriteShape", typeof(SpriteShapeController))]
internal class SpriteShapeEditorTool : PathEditorTool<CustomPath>
{
private static InternalEditorBridge.ShortcutContext m_ShortcutContext;
public static SpriteShapeEditorTool activeSpriteShapeEditorTool
{
get
{
if (m_ShortcutContext != null)
return m_ShortcutContext.context as SpriteShapeEditorTool;
return null;
}
}
protected override bool GetLinearTangentIsZero(UnityEngine.Object target)
{
return true;
}
protected override IDrawer GetCustomDrawer(UnityEngine.Object target)
{
return new CustomDrawer(target as SpriteShapeController);
}
protected override IShape GetShape(UnityEngine.Object target)
{
return Polygon.empty;
}
protected override void Initialize(CustomPath shapeEditor, SerializedObject serializedObject)
{
var controller = serializedObject.targetObject as SpriteShapeController;
var spline = controller.spline;
shapeEditor.shapeType = ShapeType.Spline;
shapeEditor.isOpenEnded = spline.isOpenEnded;
for (var i = 0; i < spline.GetPointCount(); ++i)
{
var position = spline.GetPosition(i);
shapeEditor.AddPoint(new ControlPoint()
{
position = spline.GetPosition(i),
localLeftTangent = spline.GetLeftTangent(i),
localRightTangent = spline.GetRightTangent(i),
tangentMode = (TangentMode)spline.GetTangentMode(i)
});
shapeEditor.SetData(i, new SpriteShapeData()
{
spriteIndex = spline.GetSpriteIndex(i),
height = spline.GetHeight(i),
corner = spline.GetCorner(i)
});
}
shapeEditor.UpdateTangentsFromMode();
}
protected override void SetShape(CustomPath shapeEditor, SerializedObject serializedObject)
{
serializedObject.Update();
var controller = serializedObject.targetObject as SpriteShapeController;
var splineProp = serializedObject.FindProperty("m_Spline");
var controlPointsProp = splineProp.FindPropertyRelative("m_ControlPoints");
splineProp.FindPropertyRelative("m_IsOpenEnded").boolValue = shapeEditor.isOpenEnded;
controlPointsProp.arraySize = shapeEditor.pointCount;
for (var i = 0; i < shapeEditor.pointCount; ++i)
{
var elementProp = controlPointsProp.GetArrayElementAtIndex(i);
var point = shapeEditor.GetPoint(i);
var data = shapeEditor.GetData(i);
elementProp.FindPropertyRelative("position").vector3Value = point.position;
elementProp.FindPropertyRelative("leftTangent").vector3Value = point.localLeftTangent;
elementProp.FindPropertyRelative("rightTangent").vector3Value = point.localRightTangent;
elementProp.FindPropertyRelative("mode").enumValueIndex = (int)point.tangentMode;
elementProp.FindPropertyRelative("height").floatValue = data.height;
elementProp.FindPropertyRelative("spriteIndex").intValue = data.spriteIndex;
elementProp.FindPropertyRelative("corner").boolValue = data.corner;
}
serializedObject.ApplyModifiedProperties();
}
protected override void OnActivate()
{
RegisterShortcuts();
}
protected override void OnDeactivate()
{
UnregisterShortcuts();
}
private void CycleSpriteIndex()
{
foreach(var target in targets)
{
var spriteShapeController = target as SpriteShapeController;
var shapeEditor = GetPath(target);
Editor cachedEditor = null;
Editor.CreateCachedEditor(spriteShapeController, typeof(SpriteShapeControllerEditor), ref cachedEditor);
if (spriteShapeController == null || spriteShapeController.spriteShape == null || shapeEditor.selection.Count == 0 || cachedEditor == null || shapeEditor.selection.Count > 1)
continue;
var spriteShape = spriteShapeController.spriteShape;
var scEditor = cachedEditor as SpriteShapeControllerEditor;
var selected = shapeEditor.selection.elements[0];
if (shapeEditor.selection.Contains(selected))
{
shapeEditor.undoObject.RegisterUndo("Cycle Variant");
var data = shapeEditor.GetData(selected);
var angleRangeIndex = scEditor.GetAngleRange(selected);
if (angleRangeIndex != -1)
{
var angleRange = spriteShape.angleRanges[angleRangeIndex];
if (angleRange.sprites.Count > 0)
data.spriteIndex = (data.spriteIndex + 1) % angleRange.sprites.Count;
shapeEditor.SetData(selected, data);
}
SetPath(target);
}
}
}
private static float SlopeAngle(Vector2 start, Vector2 end)
{
var dir = start - end;
dir.Normalize();
var dvup = new Vector2(0, 1f);
var dvrt = new Vector2(1f, 0);
var dr = Vector2.Dot(dir, dvrt);
var du = Vector2.Dot(dir, dvup);
var cu = Mathf.Acos(du);
var sn = dr >= 0 ? 1.0f : -1.0f;
var an = cu * Mathf.Rad2Deg * sn;
// Adjust angles when direction is parallel to Up Axis.
an = (du != 1f) ? an : 0;
an = (du != -1f) ? an : -180f;
return an;
}
private void RegisterShortcuts()
{
m_ShortcutContext = new InternalEditorBridge.ShortcutContext()
{
isActive = () => GUIUtility.hotControl == 0,
context = this
};
InternalEditorBridge.RegisterShortcutContext(m_ShortcutContext);
}
private void UnregisterShortcuts()
{
InternalEditorBridge.UnregisterShortcutContext(m_ShortcutContext);
}
[Shortcut("SpriteShape Editing/Cycle Tangent Mode", typeof(InternalEditorBridge.ShortcutContext), KeyCode.M)]
private static void ShortcutCycleTangentMode(ShortcutArguments args)
{
if (args.context == m_ShortcutContext)
(m_ShortcutContext.context as SpriteShapeEditorTool).CycleTangentMode();
}
[Shortcut("SpriteShape Editing/Cycle Variant", typeof(InternalEditorBridge.ShortcutContext), KeyCode.N)]
private static void ShortcutCycleSpriteIndex(ShortcutArguments args)
{
if (args.context == m_ShortcutContext)
(m_ShortcutContext.context as SpriteShapeEditorTool).CycleSpriteIndex();
}
[Shortcut("SpriteShape Editing/Mirror Tangent", typeof(InternalEditorBridge.ShortcutContext), KeyCode.B)]
private static void ShortcutCycleMirrorTangent(ShortcutArguments args)
{
if (args.context == m_ShortcutContext)
(m_ShortcutContext.context as SpriteShapeEditorTool).MirrorTangent();
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 301b54467351d474796896b209c59cc3
timeCreated: 1503819723
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,137 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
namespace UnityEditor.U2D.SpriteShape
{
public class SpriteShapeEditorUtility
{
private static class Contents
{
public static readonly string createSpriteShapeString = "Create Sprite Shape";
public static readonly string newSpriteShapeString = "SpriteShape";
}
public const float kMaxSideSize = 2.0f;
public static UnityEngine.U2D.SpriteShape CreateSpriteShapeAsset()
{
UnityEngine.U2D.SpriteShape spriteShape = ScriptableObject.CreateInstance<UnityEngine.U2D.SpriteShape>();
ProjectWindowUtil.CreateAsset(spriteShape, "New SpriteShapeProfile.asset");
Selection.activeObject = spriteShape;
SpriteShapeEditorAnalytics.instance.eventBus.spriteShapeEvent.Invoke(spriteShape);
return spriteShape;
}
public static SpriteShapeController CreateSpriteShapeController(UnityEngine.U2D.SpriteShape shape)
{
var objName = "New SpriteShapeController";
GameObject gameObject = new GameObject(objName, typeof(SpriteShapeController));
SpriteShapeController spriteShapeController = gameObject.GetComponent<SpriteShapeController>();
spriteShapeController.spline.Clear();
if (shape != null)
objName = shape.name;
gameObject.name = GameObjectUtility.GetUniqueNameForSibling(gameObject.transform.parent, objName);
SpriteShapeEditorAnalytics.instance.eventBus.spriteShapeRendererEvent.Invoke(gameObject.GetComponent<SpriteShapeRenderer>());
return spriteShapeController;
}
public static SpriteShapeController CreateSpriteShapeControllerFromSelection()
{
var objName = "New SpriteShapeController";
GameObject gameObject = new GameObject(objName, typeof(SpriteShapeController));
SpriteShapeController spriteShapeController = gameObject.GetComponent<SpriteShapeController>();
if (Selection.activeObject is UnityEngine.U2D.SpriteShape)
{
spriteShapeController.spriteShape = (UnityEngine.U2D.SpriteShape)Selection.activeObject;
objName = spriteShapeController.spriteShape.name;
}
else if (Selection.activeObject is GameObject)
{
var activeGO = (GameObject)Selection.activeObject;
var prefabType = PrefabUtility.GetPrefabAssetType(activeGO);
if (prefabType != PrefabAssetType.Regular && prefabType != PrefabAssetType.Model)
{
GameObjectUtility.SetParentAndAlign(gameObject, activeGO);
}
}
gameObject.name = GameObjectUtility.GetUniqueNameForSibling(gameObject.transform.parent, objName);
Undo.RegisterCreatedObjectUndo(gameObject, Contents.createSpriteShapeString);
Selection.activeGameObject = gameObject;
spriteShapeController.spline.Clear();
SpriteShapeEditorAnalytics.instance.eventBus.spriteShapeRendererEvent.Invoke(gameObject.GetComponent<SpriteShapeRenderer>());
return spriteShapeController;
}
public static void SetShapeFromAsset(SpriteShapeController spriteShapeController)
{
UnityEngine.U2D.SpriteShape spriteShape = spriteShapeController.spriteShape;
if (!spriteShape)
{
SpriteShapeEditorUtility.SetToSquare(spriteShapeController);
return;
}
if (spriteShape.angleRanges.Count == 1 && spriteShape.angleRanges[0].end - spriteShape.angleRanges[0].start == 360f)
SpriteShapeEditorUtility.SetToLine(spriteShapeController);
else if (spriteShape.angleRanges.Count < 8)
SpriteShapeEditorUtility.SetToSquare(spriteShapeController);
else
SpriteShapeEditorUtility.SetToOctogon(spriteShapeController);
}
static void SetToSquare(SpriteShapeController spriteShapeController)
{
spriteShapeController.spline.Clear();
spriteShapeController.spline.InsertPointAt(0, new Vector3(-kMaxSideSize, -kMaxSideSize, 0));
spriteShapeController.spline.InsertPointAt(1, new Vector3(-kMaxSideSize, kMaxSideSize, 0));
spriteShapeController.spline.InsertPointAt(2, new Vector3(kMaxSideSize, kMaxSideSize, 0));
spriteShapeController.spline.InsertPointAt(3, new Vector3(kMaxSideSize, -kMaxSideSize, 0));
}
static void SetToLine(SpriteShapeController spriteShapeController)
{
spriteShapeController.spline.Clear();
spriteShapeController.spline.InsertPointAt(0, new Vector3(-kMaxSideSize, 0.0f, 0));
spriteShapeController.spline.InsertPointAt(1, new Vector3(kMaxSideSize, 0.0f, 0));
spriteShapeController.spline.isOpenEnded = true;
}
static void SetToOctogon(SpriteShapeController spriteShapeController)
{
float kMaxSideSizeHalf = kMaxSideSize * 0.5f;
spriteShapeController.spline.Clear();
spriteShapeController.spline.InsertPointAt(0, new Vector3(-kMaxSideSizeHalf, -kMaxSideSize, 0));
spriteShapeController.spline.InsertPointAt(1, new Vector3(-kMaxSideSize, -kMaxSideSizeHalf, 0));
spriteShapeController.spline.InsertPointAt(2, new Vector3(-kMaxSideSize, kMaxSideSizeHalf, 0));
spriteShapeController.spline.InsertPointAt(3, new Vector3(-kMaxSideSizeHalf, kMaxSideSize, 0));
spriteShapeController.spline.InsertPointAt(4, new Vector3(kMaxSideSizeHalf, kMaxSideSize, 0));
spriteShapeController.spline.InsertPointAt(5, new Vector3(kMaxSideSize, kMaxSideSizeHalf, 0));
spriteShapeController.spline.InsertPointAt(6, new Vector3(kMaxSideSize, -kMaxSideSizeHalf, 0));
spriteShapeController.spline.InsertPointAt(7, new Vector3(kMaxSideSizeHalf, -kMaxSideSize, 0));
}
public static int GetRangeIndexFromAngle(UnityEngine.U2D.SpriteShape spriteShape, float angle)
{
return GetRangeIndexFromAngle(spriteShape.angleRanges, angle);
}
public static int GetRangeIndexFromAngle(List<AngleRange> angleRanges, float angle)
{
for (int i = 0; i < angleRanges.Count; ++i)
{
var angleRange = angleRanges[i];
var range = angleRange.end - angleRange.start;
var angle2 = Mathf.Repeat(angle - angleRange.start, 360f);
if (angle2 >= 0f && angle2 <= range)
return i;
}
return -1;
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 465d9bad157c4de4994f6d05a8f9d38a
timeCreated: 1504685545
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,349 @@
using UnityEditor;
using UnityEngine;
using UnityEditor.Sprites;
using System.Collections;
using System.Collections.Generic;
namespace UnityEditor.U2D
{
public class SpriteShapeHandleUtility
{
private class Styles
{
public Texture playheadTex;
public Texture handRightTex;
public Texture handLeftTex;
}
private static Styles s_Styles;
private static Styles styles
{
get
{
if (s_Styles == null)
s_Styles = new Styles();
return s_Styles;
}
}
static private Material s_HandleWireMaterial;
private static Material handleWireMaterial
{
get
{
if (!s_HandleWireMaterial)
s_HandleWireMaterial = (Material)EditorGUIUtility.LoadRequired("SceneView/2DHandleLines.mat");
return s_HandleWireMaterial;
}
}
private static Material s_FillTextureMaterial;
private static Material fillTextureMaterial
{
get
{
if (s_FillTextureMaterial == null)
{
s_FillTextureMaterial = new Material(Shader.Find("Hidden/InternalSpritesInspector"));
s_FillTextureMaterial.hideFlags = HideFlags.DontSave;
}
s_FillTextureMaterial.SetFloat("_AdjustLinearForGamma", PlayerSettings.colorSpace == ColorSpace.Linear ? 1.0f : 0.0f);
return s_FillTextureMaterial;
}
}
private static Mesh s_TextureCapMesh;
private static Mesh textureCapMesh
{
get
{
if (s_TextureCapMesh == null)
{
s_TextureCapMesh = new Mesh();
s_TextureCapMesh.hideFlags = HideFlags.DontSave;
s_TextureCapMesh.vertices = new Vector3[] {
new Vector2(-0.5f, -0.5f),
new Vector2(-0.5f, 0.5f),
new Vector2(0.5f, 0.5f),
new Vector2(-0.5f, -0.5f),
new Vector2(0.5f, 0.5f),
new Vector2(0.5f, -0.5f)
};
s_TextureCapMesh.uv = new Vector2[] {
Vector3.zero,
Vector3.up,
Vector3.up + Vector3.right,
Vector3.zero,
Vector3.up + Vector3.right,
Vector3.right
};
s_TextureCapMesh.SetTriangles(new int[] { 0, 1, 2, 3, 4, 5 }, 0);
}
return s_TextureCapMesh;
}
}
private static readonly Vector3[] s_WireArcPoints = new Vector3[60];
public static float PosToAngle(Vector2 position, Vector2 center, float angleOffset)
{
Vector2 dir = (Quaternion.AngleAxis(angleOffset, Vector3.forward) * (position - center)).normalized;
return Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
}
public static Vector2 Slider2D(int id, Vector2 position, Vector3 capOffset, Quaternion rotation, float size, Handles.CapFunction drawCapFunction)
{
return Handles.Slider2D(id, position, capOffset, Vector3.forward, rotation * Vector3.up, rotation * Vector3.right, size, drawCapFunction, Vector2.zero);
}
public static void DrawRangeOutline(float start, float end, float angleOffset, Vector2 center, float radius, float width)
{
Vector3 startVec = Quaternion.AngleAxis(start + angleOffset, Vector3.forward) * Vector3.right;
Vector3 endVec = Quaternion.AngleAxis(end + angleOffset, Vector3.forward) * Vector3.right;
Handles.DrawWireArc(center, Vector3.forward, startVec, end - start, radius - width);
Handles.DrawWireArc(center, Vector3.forward, startVec, end - start, radius);
Handles.DrawLine(startVec * (radius - width) + (Vector3)center, startVec * radius + (Vector3)center);
Handles.DrawLine(endVec * (radius - width) + (Vector3)center, endVec * radius + (Vector3)center);
}
private static void ApplyWireMaterial()
{
UnityEngine.Rendering.CompareFunction zTest = UnityEngine.Rendering.CompareFunction.Always;
ApplyWireMaterial(zTest);
}
private static void ApplyWireMaterial(UnityEngine.Rendering.CompareFunction zTest)
{
Material mat = handleWireMaterial;
mat.SetInt("_HandleZTest", (int)zTest);
mat.SetPass(0);
}
static void SetDiscSectionPoints(Vector3[] dest, Vector3 center, Vector3 normal, Vector3 from, float angle, float radius)
{
Vector3 fromn = from.normalized;
Quaternion r = Quaternion.AngleAxis(angle / (float)(dest.Length - 1), normal);
Vector3 tangent = fromn * radius;
for (int i = 0; i < dest.Length; i++)
{
dest[i] = center + tangent;
tangent = r * tangent;
}
}
public static void DrawSolidArc(Vector3 center, Vector3 normal, Vector3 from, float angle, float radius, float width)
{
if (Event.current.type != EventType.Repaint)
return;
SetDiscSectionPoints(s_WireArcPoints, center, normal, from, angle, radius);
Shader.SetGlobalColor("_HandleColor", Handles.color);
Shader.SetGlobalFloat("_HandleSize", 1);
ApplyWireMaterial(Handles.zTest);
float widthPercentage = 1f - Mathf.Clamp01(width / radius);
// Draw it twice to ensure backface culling doesn't hide any of the faces
GL.PushMatrix();
GL.MultMatrix(Handles.matrix);
GL.Begin(GL.TRIANGLES);
for (int i = 1, count = s_WireArcPoints.Length; i < count; ++i)
{
Vector3 d1 = s_WireArcPoints[i - 1] - center;
Vector3 d2 = s_WireArcPoints[i] - center;
GL.Color(Handles.color);
GL.Vertex(d1 * widthPercentage + center);
GL.Vertex(s_WireArcPoints[i - 1]);
GL.Vertex(s_WireArcPoints[i]);
GL.Vertex(d1 * widthPercentage + center);
GL.Vertex(s_WireArcPoints[i]);
GL.Vertex(d2 * widthPercentage + center);
GL.Vertex(d1 * widthPercentage + center);
GL.Vertex(s_WireArcPoints[i]);
GL.Vertex(s_WireArcPoints[i - 1]);
GL.Vertex(d1 * widthPercentage + center);
GL.Vertex(d2 * widthPercentage + center);
GL.Vertex(s_WireArcPoints[i]);
}
GL.End();
GL.PopMatrix();
}
public static void DrawTextureArc(Texture texture, float pixelsPerRadius, Vector3 center, Vector3 normal, Vector3 from, float angle, float radius)
{
if (Event.current.type != EventType.Repaint || !texture)
return;
SetDiscSectionPoints(s_WireArcPoints, Vector3.zero, normal, from, angle, 0.5f);
fillTextureMaterial.mainTexture = texture;
fillTextureMaterial.mainTextureScale = new Vector2(1f, -1f);
fillTextureMaterial.mainTextureOffset = Vector2.zero;
fillTextureMaterial.SetPass(0);
Matrix4x4 matrix = new Matrix4x4();
matrix.SetTRS(center, Quaternion.identity, new Vector3(radius, radius, 1) * 2f);
Vector3 texOffset = Vector2.one * 0.5f;
float scale = pixelsPerRadius / radius;
GL.PushMatrix();
GL.LoadPixelMatrix();
GL.MultMatrix(matrix);
GL.Begin(GL.TRIANGLES);
for (int i = 1, count = s_WireArcPoints.Length; i < count; ++i)
{
GL.Color(Handles.color);
GL.TexCoord(texOffset);
GL.Vertex(Vector3.zero);
GL.TexCoord(s_WireArcPoints[i - 1] * scale + texOffset);
GL.Vertex(s_WireArcPoints[i - 1]);
GL.TexCoord(s_WireArcPoints[i] * scale + texOffset);
GL.Vertex(s_WireArcPoints[i]);
GL.TexCoord(texOffset);
GL.Vertex(Vector3.zero);
GL.TexCoord(s_WireArcPoints[i] * scale + texOffset);
GL.Vertex(s_WireArcPoints[i]);
GL.TexCoord(s_WireArcPoints[i - 1] * scale + texOffset);
GL.Vertex(s_WireArcPoints[i - 1]);
}
GL.End();
GL.PopMatrix();
}
public static void PlayHeadCap(int controlID, Vector3 position, Quaternion rotation, float size, EventType eventType)
{
if (styles.playheadTex == null)
styles.playheadTex = AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.spriteshape/Editor/Handles/ss_playhead.png");
GUITextureCap(controlID, styles.playheadTex, position, rotation, size, eventType);
}
public static void RangeLeftCap(int controlID, Vector3 position, Quaternion rotation, float size, EventType eventType)
{
if (styles.handLeftTex == null)
styles.handLeftTex = AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.spriteshape/Editor/Handles/ss_leftrange.png");
GUITextureCap(controlID, styles.handLeftTex, position, rotation, size, eventType);
}
public static void RangeRightCap(int controlID, Vector3 position, Quaternion rotation, float size, EventType eventType)
{
if (styles.handRightTex == null)
styles.handRightTex = AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.spriteshape/Editor/Handles/ss_rightrange.png");
GUITextureCap(controlID, styles.handRightTex, position, rotation, size, eventType);
}
public static void GUITextureCap(int controlID, Texture texture, Vector3 position, Quaternion rotation, float size, EventType eventType)
{
switch (eventType)
{
case (EventType.Layout):
HandleUtility.AddControl(controlID, DistanceToRectangle(position, rotation, Vector2.one * size * 0.5f));
break;
case (EventType.Repaint):
FilterMode filterMode = texture.filterMode;
texture.filterMode = FilterMode.Bilinear;
EditorSpriteGUIUtility.spriteMaterial.mainTexture = texture;
float w = (float)texture.width;
float h = (float)texture.height;
float max = Mathf.Max(w, h);
Vector3 scale = new Vector2(w / max, h / max) * size;
if (Camera.current == null)
scale.y *= -1f;
EditorSpriteGUIUtility.DrawMesh(textureCapMesh, EditorSpriteGUIUtility.spriteMaterial, position, rotation, scale);
texture.filterMode = filterMode;
break;
}
}
public static float DistanceToArcWidth(Vector2 position, Vector2 center, float start, float end, float radius, float width, float angleOffet)
{
float innerRadius = radius - width;
float angle = PosToAngle(position, center, -angleOffet);
angle = Mathf.Repeat(angle - start, 360f);
float range = end - start;
if (angle >= 0f && angle <= range)
{
float distanceToCenter = (position - center).magnitude;
if (distanceToCenter <= radius && distanceToCenter >= innerRadius)
return 0f;
else if (distanceToCenter > radius)
return distanceToCenter - radius;
else if (distanceToCenter < innerRadius)
return innerRadius - distanceToCenter;
}
else if (angle < 0f)
{
Vector2 pos1 = (Vector2)(Quaternion.AngleAxis(start + angleOffet, Vector3.forward) * Vector3.right * radius) + center;
Vector2 pos2 = (Vector2)(Quaternion.AngleAxis(start + angleOffet, Vector3.forward) * Vector3.right * innerRadius) + center;
return Mathf.Min((position - pos1).magnitude, (position - pos2).magnitude);
}
else if (angle > range)
{
Vector2 pos1 = (Vector2)(Quaternion.AngleAxis(end + angleOffet, Vector3.forward) * Vector3.right * radius) + center;
Vector2 pos2 = (Vector2)(Quaternion.AngleAxis(end + angleOffet, Vector3.forward) * Vector3.right * innerRadius) + center;
return Mathf.Min((position - pos1).magnitude, (position - pos2).magnitude);
}
return float.MaxValue;
}
public static float DistanceToRectangle(Vector3 position, Quaternion rotation, Vector2 size)
{
Vector3[] points = { Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero };
Vector3 sideways = rotation * new Vector3(size.x, 0, 0);
Vector3 up = rotation * new Vector3(0, size.y, 0);
points[0] = HandleUtility.WorldToGUIPoint(position + sideways + up);
points[1] = HandleUtility.WorldToGUIPoint(position + sideways - up);
points[2] = HandleUtility.WorldToGUIPoint(position - sideways - up);
points[3] = HandleUtility.WorldToGUIPoint(position - sideways + up);
points[4] = points[0];
Vector2 pos = Event.current.mousePosition;
bool oddNodes = false;
int j = 4;
for (int i = 0; i < 5; i++)
{
if ((points[i].y > pos.y) != (points[j].y > pos.y))
{
if (pos.x < (points[j].x - points[i].x) * (pos.y - points[i].y) / (points[j].y - points[i].y) + points[i].x)
{
oddNodes = !oddNodes;
}
}
j = i;
}
if (!oddNodes)
{
// Distance to closest edge (not so fast)
float dist, closestDist = -1f;
j = 1;
for (int i = 0; i < 4; i++)
{
dist = HandleUtility.DistancePointToLineSegment(pos, points[i], points[j++]);
if (dist < closestDist || closestDist < 0)
closestDist = dist;
}
return closestDist;
}
else
return 0;
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 3c4c6b04b82bb68428942652e2972a8c
timeCreated: 1505446713
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,21 @@
{
"name": "Unity.2D.SpriteShape.Editor",
"references": [
"Unity.InternalAPIEditorBridge.001",
"Unity.2D.Common.Editor",
"Unity.2D.Common.Runtime",
"Unity.2D.SpriteShape.Runtime",
"Unity.2D.Path.Editor"
],
"optionalUnityReferences": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": []
}

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: bfbb4a459210651499d21f444f9b55fd
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: