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