/******************************************************************************
|
* Spine Runtimes License Agreement
|
* Last updated July 28, 2023. Replaces all prior versions.
|
*
|
* Copyright (c) 2013-2023, Esoteric Software LLC
|
*
|
* Integration of the Spine Runtimes into software or otherwise creating
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
* http://esotericsoftware.com/spine-editor-license
|
*
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
|
* otherwise create derivative works of the Spine Runtimes (collectively,
|
* "Products"), provided that each user of the Products must obtain their own
|
* Spine Editor license and redistribution of the Products in any form must
|
* include this license and copyright notice.
|
*
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
|
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
*****************************************************************************/
|
|
#pragma warning disable 0219
|
|
#if UNITY_2022_1_OR_NEWER
|
#define FREE_MOVE_HANDLE_HAS_NO_ROTATION_PARAM
|
#endif
|
|
#define SPINE_SKELETONMECANIM
|
|
using System.Collections.Generic;
|
using System.Globalization;
|
using System.IO;
|
using System.Linq;
|
using System.Reflection;
|
using System.Text;
|
using UnityEditor;
|
using UnityEngine;
|
|
namespace Spine.Unity.Editor {
|
using EventType = UnityEngine.EventType;
|
|
public static class SpineHandles {
|
public static Color BoneColor { get { return new Color(0.8f, 0.8f, 0.8f, 0.4f); } }
|
public static Color PathColor { get { return new Color(254 / 255f, 127 / 255f, 0); } }
|
public static Color TransformContraintColor { get { return new Color(170 / 255f, 226 / 255f, 35 / 255f); } }
|
public static Color IkColor { get { return new Color(228 / 255f, 90 / 255f, 43 / 255f); } }
|
public static Color PointColor { get { return new Color(1f, 1f, 0f, 1f); } }
|
|
static Vector3[] _boneMeshVerts = {
|
new Vector3(0, 0, 0),
|
new Vector3(0.1f, 0.1f, 0),
|
new Vector3(1, 0, 0),
|
new Vector3(0.1f, -0.1f, 0)
|
};
|
static Mesh _boneMesh;
|
public static Mesh BoneMesh {
|
get {
|
if (_boneMesh == null) {
|
_boneMesh = new Mesh {
|
vertices = _boneMeshVerts,
|
uv = new Vector2[4],
|
triangles = new[] { 0, 1, 2, 2, 3, 0 }
|
};
|
_boneMesh.RecalculateBounds();
|
_boneMesh.RecalculateNormals();
|
}
|
return _boneMesh;
|
}
|
}
|
|
static Mesh _arrowheadMesh;
|
public static Mesh ArrowheadMesh {
|
get {
|
if (_arrowheadMesh == null) {
|
_arrowheadMesh = new Mesh {
|
vertices = new[] {
|
new Vector3(0, 0),
|
new Vector3(-0.1f, 0.05f),
|
new Vector3(-0.1f, -0.05f)
|
},
|
uv = new Vector2[3],
|
triangles = new[] { 0, 1, 2 }
|
};
|
_arrowheadMesh.RecalculateBounds();
|
_arrowheadMesh.RecalculateNormals();
|
}
|
return _arrowheadMesh;
|
}
|
}
|
|
static Material _boneMaterial;
|
static Material BoneMaterial {
|
get {
|
if (_boneMaterial == null) {
|
_boneMaterial = new Material(Shader.Find("Hidden/Spine/Bones"));
|
_boneMaterial.SetColor("_Color", SpineHandles.BoneColor);
|
}
|
|
return _boneMaterial;
|
}
|
}
|
public static Material GetBoneMaterial () {
|
BoneMaterial.SetColor("_Color", SpineHandles.BoneColor);
|
return BoneMaterial;
|
}
|
|
public static Material GetBoneMaterial (Color color) {
|
BoneMaterial.SetColor("_Color", color);
|
return BoneMaterial;
|
}
|
|
static Material _ikMaterial;
|
public static Material IKMaterial {
|
get {
|
if (_ikMaterial == null) {
|
_ikMaterial = new Material(Shader.Find("Hidden/Spine/Bones"));
|
_ikMaterial.SetColor("_Color", SpineHandles.IkColor);
|
}
|
return _ikMaterial;
|
}
|
}
|
|
static GUIStyle _boneNameStyle;
|
public static GUIStyle BoneNameStyle {
|
get {
|
if (_boneNameStyle == null) {
|
_boneNameStyle = new GUIStyle(EditorStyles.whiteMiniLabel) {
|
alignment = TextAnchor.MiddleCenter,
|
stretchWidth = true,
|
padding = new RectOffset(0, 0, 0, 0),
|
contentOffset = new Vector2(-5f, 0f)
|
};
|
}
|
return _boneNameStyle;
|
}
|
}
|
|
static GUIStyle _pathNameStyle;
|
public static GUIStyle PathNameStyle {
|
get {
|
if (_pathNameStyle == null) {
|
_pathNameStyle = new GUIStyle(SpineHandles.BoneNameStyle);
|
_pathNameStyle.normal.textColor = SpineHandles.PathColor;
|
}
|
return _pathNameStyle;
|
}
|
}
|
|
static GUIStyle _pointNameStyle;
|
public static GUIStyle PointNameStyle {
|
get {
|
if (_pointNameStyle == null) {
|
_pointNameStyle = new GUIStyle(SpineHandles.BoneNameStyle);
|
_pointNameStyle.normal.textColor = SpineHandles.PointColor;
|
}
|
return _pointNameStyle;
|
}
|
}
|
|
public static void DrawBoneNames (Transform transform, Skeleton skeleton, float positionScale = 1f,
|
Vector2? positionOffset = null) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
Vector2 offset = positionOffset == null ? Vector2.zero : positionOffset.Value;
|
GUIStyle style = BoneNameStyle;
|
foreach (Bone b in skeleton.Bones) {
|
if (!b.Active) continue;
|
Vector3 pos = new Vector3(b.WorldX * positionScale + offset.x, b.WorldY * positionScale + offset.y, 0)
|
+ (new Vector3(b.A, b.C) * (b.Data.Length * 0.5f));
|
pos = transform.TransformPoint(pos);
|
Handles.Label(pos, b.Data.Name, style);
|
}
|
}
|
|
public static void DrawBones (Transform transform, Skeleton skeleton, float positionScale = 1f,
|
Vector2? positionOffset = null) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
Vector2 offset = positionOffset == null ? Vector2.zero : positionOffset.Value;
|
float boneScale = 1.8f; // Draw the root bone largest;
|
DrawCrosshairs2D(skeleton.Bones.Items[0].GetWorldPosition(transform, positionScale, offset), 0.08f, positionScale);
|
|
foreach (Bone b in skeleton.Bones) {
|
if (!b.Active) continue;
|
DrawBone(transform, b, boneScale, positionScale, positionOffset);
|
boneScale = 1f;
|
}
|
}
|
|
static Vector3[] _boneWireBuffer = new Vector3[5];
|
static Vector3[] GetBoneWireBuffer (Matrix4x4 m) {
|
for (int i = 0, n = _boneMeshVerts.Length; i < n; i++)
|
_boneWireBuffer[i] = m.MultiplyPoint(_boneMeshVerts[i]);
|
|
_boneWireBuffer[4] = _boneWireBuffer[0]; // closed polygon.
|
return _boneWireBuffer;
|
}
|
public static void DrawBoneWireframe (Transform transform, Bone b, Color color, float skeletonRenderScale = 1f,
|
Vector2? positionOffset = null) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
Vector2 offset = positionOffset == null ? Vector2.zero : positionOffset.Value;
|
Handles.color = color;
|
Vector3 pos = new Vector3(b.WorldX * skeletonRenderScale + offset.x, b.WorldY * skeletonRenderScale + offset.y, 0);
|
float length = b.Data.Length;
|
|
if (length > 0) {
|
Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX);
|
Vector3 scale = Vector3.one * length * b.WorldScaleX * skeletonRenderScale;
|
const float my = 1.5f;
|
scale.y *= (SpineEditorUtilities.Preferences.handleScale + 1) * 0.5f;
|
scale.y = Mathf.Clamp(scale.x, -my * skeletonRenderScale, my * skeletonRenderScale);
|
Handles.DrawPolyLine(GetBoneWireBuffer(transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale)));
|
Vector3 wp = transform.TransformPoint(pos);
|
DrawBoneCircle(wp, color, transform.forward, skeletonRenderScale);
|
} else {
|
Vector3 wp = transform.TransformPoint(pos);
|
DrawBoneCircle(wp, color, transform.forward, skeletonRenderScale);
|
}
|
}
|
|
public static void DrawBone (Transform transform, Bone b, float boneScale, float skeletonRenderScale = 1f,
|
Vector2? positionOffset = null) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
Vector2 offset = positionOffset == null ? Vector2.zero : positionOffset.Value;
|
Vector3 pos = new Vector3(b.WorldX * skeletonRenderScale + offset.x, b.WorldY * skeletonRenderScale + offset.y, 0);
|
float length = b.Data.Length;
|
if (length > 0) {
|
Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX);
|
Vector3 scale = Vector3.one * length * b.WorldScaleX * skeletonRenderScale;
|
const float my = 1.5f;
|
scale.y *= (SpineEditorUtilities.Preferences.handleScale + 1f) * 0.5f;
|
scale.y = Mathf.Clamp(scale.x, -my * skeletonRenderScale, my * skeletonRenderScale);
|
SpineHandles.GetBoneMaterial().SetPass(0);
|
Graphics.DrawMeshNow(SpineHandles.BoneMesh, transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale));
|
} else {
|
Vector3 wp = transform.TransformPoint(pos);
|
DrawBoneCircle(wp, SpineHandles.BoneColor, transform.forward, boneScale * skeletonRenderScale);
|
}
|
}
|
|
public static void DrawBone (Transform transform, Bone b, float boneScale, Color color, float skeletonRenderScale = 1f,
|
Vector2? positionOffset = null) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
Vector2 offset = positionOffset == null ? Vector2.zero : positionOffset.Value;
|
Vector3 pos = new Vector3(b.WorldX * skeletonRenderScale + offset.x, b.WorldY * skeletonRenderScale + offset.y, 0);
|
float length = b.Data.Length;
|
if (length > 0) {
|
Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX);
|
Vector3 scale = Vector3.one * length * b.WorldScaleX;
|
const float my = 1.5f;
|
scale.y *= (SpineEditorUtilities.Preferences.handleScale + 1f) * 0.5f;
|
scale.y = Mathf.Clamp(scale.x, -my, my);
|
SpineHandles.GetBoneMaterial(color).SetPass(0);
|
Graphics.DrawMeshNow(SpineHandles.BoneMesh, transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale));
|
} else {
|
Vector3 wp = transform.TransformPoint(pos);
|
DrawBoneCircle(wp, color, transform.forward, boneScale * skeletonRenderScale);
|
}
|
}
|
|
public static void DrawPaths (Transform transform, Skeleton skeleton) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
foreach (Slot s in skeleton.DrawOrder) {
|
PathAttachment p = s.Attachment as PathAttachment;
|
if (p != null) SpineHandles.DrawPath(s, p, transform, true);
|
}
|
}
|
|
static float[] pathVertexBuffer;
|
public static void DrawPath (Slot s, PathAttachment p, Transform t, bool includeName) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
int worldVerticesLength = p.WorldVerticesLength;
|
|
if (pathVertexBuffer == null || pathVertexBuffer.Length < worldVerticesLength)
|
pathVertexBuffer = new float[worldVerticesLength];
|
|
float[] pv = pathVertexBuffer;
|
p.ComputeWorldVertices(s, pv);
|
|
Color ocolor = Handles.color;
|
Handles.color = SpineHandles.PathColor;
|
|
Matrix4x4 m = t.localToWorldMatrix;
|
const int step = 6;
|
int n = worldVerticesLength - step;
|
Vector3 p0, p1, p2, p3;
|
for (int i = 2; i < n; i += step) {
|
p0 = m.MultiplyPoint(new Vector3(pv[i], pv[i + 1]));
|
p1 = m.MultiplyPoint(new Vector3(pv[i + 2], pv[i + 3]));
|
p2 = m.MultiplyPoint(new Vector3(pv[i + 4], pv[i + 5]));
|
p3 = m.MultiplyPoint(new Vector3(pv[i + 6], pv[i + 7]));
|
DrawCubicBezier(p0, p1, p2, p3);
|
}
|
|
n += step;
|
if (p.Closed) {
|
p0 = m.MultiplyPoint(new Vector3(pv[n - 4], pv[n - 3]));
|
p1 = m.MultiplyPoint(new Vector3(pv[n - 2], pv[n - 1]));
|
p2 = m.MultiplyPoint(new Vector3(pv[0], pv[1]));
|
p3 = m.MultiplyPoint(new Vector3(pv[2], pv[3]));
|
DrawCubicBezier(p0, p1, p2, p3);
|
}
|
|
const float endCapSize = 0.05f;
|
Vector3 firstPoint = m.MultiplyPoint(new Vector3(pv[2], pv[3]));
|
SpineHandles.DrawDot(firstPoint, endCapSize);
|
|
//if (!p.Closed) SpineHandles.DrawDot(m.MultiplyPoint(new Vector3(pv[n - 4], pv[n - 3])), endCapSize);
|
if (includeName) Handles.Label(firstPoint + new Vector3(0, 0.1f), p.Name, PathNameStyle);
|
|
Handles.color = ocolor;
|
}
|
|
public static void DrawDot (Vector3 position, float size) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
Handles.DotHandleCap(0, position, Quaternion.identity, size * HandleUtility.GetHandleSize(position), EventType.Ignore); //Handles.DotCap(0, position, Quaternion.identity, size * HandleUtility.GetHandleSize(position));
|
}
|
|
public static void DrawBoundingBoxes (Transform transform, Skeleton skeleton) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
foreach (Slot slot in skeleton.Slots) {
|
BoundingBoxAttachment bba = slot.Attachment as BoundingBoxAttachment;
|
if (bba != null) SpineHandles.DrawBoundingBox(slot, bba, transform);
|
}
|
}
|
|
public static void DrawBoundingBox (Slot slot, BoundingBoxAttachment box, Transform t) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
if (box.Vertices.Length <= 2) return; // Handle cases where user creates a BoundingBoxAttachment but doesn't actually define it.
|
|
float[] worldVerts = new float[box.WorldVerticesLength];
|
box.ComputeWorldVertices(slot, worldVerts);
|
|
Handles.color = Color.green;
|
Vector3 lastVert = Vector3.zero;
|
Vector3 vert = Vector3.zero;
|
Vector3 firstVert = t.TransformPoint(new Vector3(worldVerts[0], worldVerts[1], 0));
|
for (int i = 0; i < worldVerts.Length; i += 2) {
|
vert.x = worldVerts[i];
|
vert.y = worldVerts[i + 1];
|
vert.z = 0;
|
|
vert = t.TransformPoint(vert);
|
|
if (i > 0)
|
Handles.DrawLine(lastVert, vert);
|
|
lastVert = vert;
|
}
|
|
Handles.DrawLine(lastVert, firstVert);
|
}
|
|
public static void DrawPointAttachment (Bone bone, PointAttachment pointAttachment, Transform skeletonTransform) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
if (bone == null) return;
|
if (pointAttachment == null) return;
|
|
Vector2 localPos;
|
pointAttachment.ComputeWorldPosition(bone, out localPos.x, out localPos.y);
|
float localRotation = pointAttachment.ComputeWorldRotation(bone);
|
Matrix4x4 m = Matrix4x4.TRS(localPos, Quaternion.Euler(0, 0, localRotation), Vector3.one) * Matrix4x4.TRS(Vector3.right * 0.25f, Quaternion.identity, Vector3.one);
|
|
DrawBoneCircle(skeletonTransform.TransformPoint(localPos), SpineHandles.PointColor, Vector3.back, 1.3f);
|
DrawArrowhead(skeletonTransform.localToWorldMatrix * m);
|
}
|
|
public static void DrawConstraints (Transform transform, Skeleton skeleton, float skeletonRenderScale = 1f,
|
Vector2? positionOffset = null) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
Vector2 offset = positionOffset == null ? Vector2.zero : positionOffset.Value;
|
Vector3 targetPos;
|
Vector3 pos;
|
bool active;
|
Color handleColor;
|
const float Thickness = 4f;
|
Vector3 normal = transform.forward;
|
|
// Transform Constraints
|
handleColor = SpineHandles.TransformContraintColor;
|
foreach (TransformConstraint tc in skeleton.TransformConstraints) {
|
Bone targetBone = tc.Target;
|
targetPos = targetBone.GetWorldPosition(transform, skeletonRenderScale, offset);
|
|
if (tc.MixX > 0 || tc.MixY > 0) {
|
if ((tc.MixX > 0 && tc.MixX != 1f) ||
|
(tc.MixY > 0 && tc.MixY != 1f)) {
|
Handles.color = handleColor;
|
foreach (Bone b in tc.Bones) {
|
pos = b.GetWorldPosition(transform, skeletonRenderScale, offset);
|
Handles.DrawDottedLine(targetPos, pos, Thickness);
|
}
|
}
|
SpineHandles.DrawBoneCircle(targetPos, handleColor, normal, 1.3f * skeletonRenderScale);
|
Handles.color = handleColor;
|
SpineHandles.DrawCrosshairs(targetPos, 0.2f, targetBone.A, targetBone.B, targetBone.C, targetBone.D, transform, skeletonRenderScale);
|
}
|
}
|
|
// IK Constraints
|
handleColor = SpineHandles.IkColor;
|
foreach (IkConstraint ikc in skeleton.IkConstraints) {
|
Bone targetBone = ikc.Target;
|
targetPos = targetBone.GetWorldPosition(transform, skeletonRenderScale, offset);
|
ExposedList<Bone> bones = ikc.Bones;
|
active = ikc.Mix > 0;
|
if (active) {
|
pos = bones.Items[0].GetWorldPosition(transform, skeletonRenderScale, offset);
|
switch (bones.Count) {
|
case 1: {
|
Handles.color = handleColor;
|
Handles.DrawLine(targetPos, pos);
|
SpineHandles.DrawBoneCircle(targetPos, handleColor, normal);
|
Matrix4x4 m = bones.Items[0].GetMatrix4x4();
|
m.m03 = targetBone.WorldX * skeletonRenderScale + offset.x;
|
m.m13 = targetBone.WorldY * skeletonRenderScale + offset.y;
|
SpineHandles.DrawArrowhead(transform.localToWorldMatrix * m);
|
break;
|
}
|
case 2: {
|
Bone childBone = bones.Items[1];
|
Vector3 child = childBone.GetWorldPosition(transform, skeletonRenderScale, offset);
|
Handles.color = handleColor;
|
Handles.DrawLine(child, pos);
|
Handles.DrawLine(targetPos, child);
|
SpineHandles.DrawBoneCircle(pos, handleColor, normal, 0.5f);
|
SpineHandles.DrawBoneCircle(child, handleColor, normal, 0.5f);
|
SpineHandles.DrawBoneCircle(targetPos, handleColor, normal);
|
Matrix4x4 m = childBone.GetMatrix4x4();
|
m.m03 = targetBone.WorldX * skeletonRenderScale + offset.x;
|
m.m13 = targetBone.WorldY * skeletonRenderScale + offset.y;
|
SpineHandles.DrawArrowhead(transform.localToWorldMatrix * m);
|
break;
|
}
|
}
|
}
|
//Handles.Label(targetPos, ikc.Data.Name, SpineHandles.BoneNameStyle);
|
}
|
|
// Path Constraints
|
handleColor = SpineHandles.PathColor;
|
foreach (PathConstraint pc in skeleton.PathConstraints) {
|
active = pc.MixX > 0 || pc.MixY > 0 || pc.MixRotate > 0;
|
if (active)
|
foreach (Bone b in pc.Bones)
|
SpineHandles.DrawBoneCircle(b.GetWorldPosition(transform, skeletonRenderScale, offset),
|
handleColor, normal, 1f * skeletonRenderScale);
|
}
|
}
|
|
public static void DrawReferenceRect (SkeletonGraphic skeletonGraphic, Color color) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
RectTransform rectTransform = skeletonGraphic.rectTransform;
|
Vector2 referenceRectSize = skeletonGraphic.GetReferenceRectSize();
|
|
Vector3 position = rectTransform.position;
|
Vector3 right = rectTransform.TransformVector(Vector3.right * referenceRectSize.x);
|
Vector3 up = rectTransform.TransformVector(Vector3.up * referenceRectSize.y);
|
|
Vector3 cornerVertexBL = position - rectTransform.pivot.x * right - rectTransform.pivot.y * up;
|
DrawRect(cornerVertexBL, right, up, color);
|
}
|
|
public static void DrawRectTransformRect (SkeletonGraphic skeletonGraphic, Color color) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
RectTransform rectTransform = skeletonGraphic.rectTransform;
|
Vector2 rectTransformSize = skeletonGraphic.RectTransformSize;
|
|
Vector3 position = rectTransform.position;
|
Vector3 right = rectTransform.TransformVector(Vector3.right * rectTransformSize.x);
|
Vector3 up = rectTransform.TransformVector(Vector3.up * rectTransformSize.y);
|
|
Vector3 cornerVertexBL = position - rectTransform.pivot.x * right - rectTransform.pivot.y * up;
|
DrawRect(cornerVertexBL, right, up, color);
|
}
|
|
public static void DrawRect (Vector3 cornerVertexBL, Vector3 right, Vector3 up, Color color) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
Vector3 v0 = cornerVertexBL;
|
Vector3 v1 = v0 + right;
|
Vector3 v2 = v0 + right + up;
|
Vector3 v3 = v0 + up;
|
Color previousColor = UnityEditor.Handles.color;
|
UnityEditor.Handles.color = color;
|
UnityEditor.Handles.DrawLine(v0, v1);
|
UnityEditor.Handles.DrawLine(v1, v2);
|
UnityEditor.Handles.DrawLine(v2, v3);
|
UnityEditor.Handles.DrawLine(v3, v0);
|
UnityEditor.Handles.color = previousColor;
|
}
|
|
public static void DrawPivotOffsetHandle (SkeletonGraphic skeletonGraphic, Color color) {
|
// Note: not limiting to current.type == EventType.Repaint because the FreeMoveHandle requires interaction.
|
|
float handleSize = HandleUtility.GetHandleSize(skeletonGraphic.transform.position);
|
float controlSize = handleSize * 0.3f;
|
float discSize = handleSize * 0.03f;
|
Vector3 snap = Vector3.zero;
|
Color savedColor = Handles.color;
|
|
Handles.color = color;
|
Vector2 scaledOffset = skeletonGraphic.GetScaledPivotOffset();
|
Vector3 worldSpaceOffset = skeletonGraphic.transform.TransformPoint(scaledOffset);
|
EditorGUI.BeginChangeCheck();
|
|
#if FREE_MOVE_HANDLE_HAS_NO_ROTATION_PARAM
|
Vector3 newWorldSpacePosition = Handles.FreeMoveHandle(worldSpaceOffset, controlSize, snap, Handles.CircleHandleCap);
|
#else
|
Vector3 newWorldSpacePosition = Handles.FreeMoveHandle(worldSpaceOffset, Quaternion.identity, controlSize, snap, Handles.CircleHandleCap);
|
#endif
|
if (EditorGUI.EndChangeCheck()) {
|
Undo.RecordObject(skeletonGraphic, "Change Offset to Pivot");
|
Vector3 localScaledOffset = skeletonGraphic.transform.InverseTransformPoint(newWorldSpacePosition);
|
skeletonGraphic.SetScaledPivotOffset(localScaledOffset);
|
skeletonGraphic.UpdateMeshToInstructions();
|
}
|
Handles.DrawSolidDisc(newWorldSpacePosition, skeletonGraphic.transform.forward, discSize);
|
Handles.color = savedColor;
|
}
|
|
static void DrawCrosshairs2D (Vector3 position, float scale, float skeletonRenderScale = 1f) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
scale *= SpineEditorUtilities.Preferences.handleScale * skeletonRenderScale;
|
Handles.DrawLine(position + new Vector3(-scale, 0), position + new Vector3(scale, 0));
|
Handles.DrawLine(position + new Vector3(0, -scale), position + new Vector3(0, scale));
|
}
|
|
static void DrawCrosshairs (Vector3 position, float scale, float a, float b, float c, float d, Transform transform, float skeletonRenderScale = 1f) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
scale *= SpineEditorUtilities.Preferences.handleScale * skeletonRenderScale;
|
|
Vector3 xOffset = (Vector3)(new Vector2(a, c).normalized * scale);
|
Vector3 yOffset = (Vector3)(new Vector2(b, d).normalized * scale);
|
xOffset = transform.TransformDirection(xOffset);
|
yOffset = transform.TransformDirection(yOffset);
|
|
Handles.DrawLine(position + xOffset, position - xOffset);
|
Handles.DrawLine(position + yOffset, position - yOffset);
|
}
|
|
static void DrawArrowhead2D (Vector3 pos, float localRotation, float scale = 1f) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
scale *= SpineEditorUtilities.Preferences.handleScale;
|
|
SpineHandles.IKMaterial.SetPass(0);
|
Graphics.DrawMeshNow(SpineHandles.ArrowheadMesh, Matrix4x4.TRS(pos, Quaternion.Euler(0, 0, localRotation), new Vector3(scale, scale, scale)));
|
}
|
|
static void DrawArrowhead (Vector3 pos, Quaternion worldQuaternion) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
Graphics.DrawMeshNow(SpineHandles.ArrowheadMesh, pos, worldQuaternion, 0);
|
}
|
|
static void DrawArrowhead (Matrix4x4 m) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
float s = SpineEditorUtilities.Preferences.handleScale;
|
m.m00 *= s;
|
m.m01 *= s;
|
m.m02 *= s;
|
m.m10 *= s;
|
m.m11 *= s;
|
m.m12 *= s;
|
m.m20 *= s;
|
m.m21 *= s;
|
m.m22 *= s;
|
|
SpineHandles.IKMaterial.SetPass(0);
|
Graphics.DrawMeshNow(SpineHandles.ArrowheadMesh, m);
|
}
|
|
static void DrawBoneCircle (Vector3 pos, Color outlineColor, Vector3 normal, float scale = 1f) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
scale *= SpineEditorUtilities.Preferences.handleScale;
|
|
Color o = Handles.color;
|
Handles.color = outlineColor;
|
float firstScale = 0.08f * scale;
|
Handles.DrawSolidDisc(pos, normal, firstScale);
|
const float Thickness = 0.03f;
|
float secondScale = firstScale - (Thickness * SpineEditorUtilities.Preferences.handleScale * scale);
|
|
if (secondScale > 0f) {
|
Handles.color = new Color(0.3f, 0.3f, 0.3f, 0.5f);
|
Handles.DrawSolidDisc(pos, normal, secondScale);
|
}
|
|
Handles.color = o;
|
}
|
|
internal static void DrawCubicBezier (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) {
|
if (UnityEngine.Event.current.type != EventType.Repaint) return;
|
|
Handles.DrawBezier(p0, p3, p1, p2, Handles.color, Texture2D.whiteTexture, 2f);
|
// const float dotSize = 0.01f;
|
// Quaternion q = Quaternion.identity;
|
// Handles.DotCap(0, p0, q, dotSize);
|
// Handles.DotCap(0, p1, q, dotSize);
|
// Handles.DotCap(0, p2, q, dotSize);
|
// Handles.DotCap(0, p3, q, dotSize);
|
// Handles.DrawLine(p0, p1);
|
// Handles.DrawLine(p3, p2);
|
}
|
}
|
}
|