[csharp] Port of commit f4f22cd. Added bone transform inheritance timeline. Renamed TransformMode to Inherit.

This commit is contained in:
Harald Csaszar 2024-03-27 17:27:09 +01:00
parent e78095e5c6
commit e630d1bda7
9 changed files with 139 additions and 67 deletions

View File

@ -176,7 +176,7 @@ namespace Spine {
}
public enum Property {
Rotate = 0, X, Y, ScaleX, ScaleY, ShearX, ShearY, //
Rotate = 0, X, Y, ScaleX, ScaleY, ShearX, ShearY, Inherit, //
RGB, Alpha, RGB2, //
Attachment, Deform, //
Event, DrawOrder, //
@ -980,6 +980,53 @@ namespace Spine {
}
}
/// <summary>Changes a bone's <see cref="Bone.Inherit"/>.</summary>
public class InheritTimeline : Timeline, IBoneTimeline {
public const int ENTRIES = 2;
public const int INHERIT = 1;
readonly int boneIndex;
public InheritTimeline (int frameCount, int boneIndex)
: base(frameCount, (int)Property.Inherit + "|" + boneIndex) {
this.boneIndex = boneIndex;
}
public int BoneIndex {
get {
return boneIndex;
}
}
public override int FrameEntries {
get { return ENTRIES; }
}
/// <summary>Sets the transform mode for the specified frame.</summary>
/// <param name="frame">Between 0 and <code>frameCount</code>, inclusive.</param>
/// <param name="time">The frame time in seconds.</param>
public void SetFrame (int frame, float time, Inherit inherit) {
frame *= ENTRIES;
frames[frame] = time;
frames[frame + INHERIT] = (int)inherit;
}
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend,
MixDirection direction) {
Bone bone = skeleton.bones.Items[boneIndex];
if (!bone.active) return;
float[] frames = this.frames;
if (time < frames[0]) {
if (blend == MixBlend.Setup || blend == MixBlend.First) bone.inherit = bone.data.inherit;
return;
}
bone.inherit = InheritEnum.Values[(int)frames[Search(frames, time, ENTRIES) + INHERIT]];
}
}
/// <summary>Changes a slot's <see cref="Slot.Color"/>.</summary>
public class RGBATimeline : CurveTimeline, ISlotTimeline {
public const int ENTRIES = 5;

View File

@ -52,6 +52,7 @@ namespace Spine {
internal float a, b, worldX;
internal float c, d, worldY;
internal Inherit inherit;
internal bool sorted, active;
@ -79,6 +80,9 @@ namespace Spine {
/// <summary>The local shearY.</summary>
public float ShearY { get { return shearY; } set { shearY = value; } }
/// <summary>Controls how parent world transforms affect this bone.</summary>
public Inherit Inherit { get { return inherit; } set { inherit = value; } }
/// <summary>The rotation, as calculated by any constraints.</summary>
public float AppliedRotation { get { return arotation; } set { arotation = value; } }
@ -147,6 +151,7 @@ namespace Spine {
scaleY = bone.scaleY;
shearX = bone.shearX;
shearY = bone.shearY;
inherit = bone.inherit;
}
/// <summary>Computes the world transform using the parent bone and this bone's local applied transform.</summary>
@ -192,8 +197,8 @@ namespace Spine {
worldX = pa * x + pb * y + parent.worldX;
worldY = pc * x + pd * y + parent.worldY;
switch (data.transformMode) {
case TransformMode.Normal: {
switch (inherit) {
case Inherit.Normal: {
float rx = (rotation + shearX) * MathUtils.DegRad;
float ry = (rotation + 90 + shearY) * MathUtils.DegRad;
float la = (float)Math.Cos(rx) * scaleX;
@ -206,7 +211,7 @@ namespace Spine {
d = pc * lb + pd * ld;
return;
}
case TransformMode.OnlyTranslation: {
case Inherit.OnlyTranslation: {
float rx = (rotation + shearX) * MathUtils.DegRad;
float ry = (rotation + 90 + shearY) * MathUtils.DegRad;
a = (float)Math.Cos(rx) * scaleX;
@ -215,7 +220,7 @@ namespace Spine {
d = (float)Math.Sin(ry) * scaleY;
break;
}
case TransformMode.NoRotationOrReflection: {
case Inherit.NoRotationOrReflection: {
float s = pa * pa + pc * pc, prx;
if (s > 0.0001f) {
s = Math.Abs(pa * pd - pb * pc) / s;
@ -241,8 +246,8 @@ namespace Spine {
d = pc * lb + pd * ld;
break;
}
case TransformMode.NoScale:
case TransformMode.NoScaleOrReflection: {
case Inherit.NoScale:
case Inherit.NoScaleOrReflection: {
rotation *= MathUtils.DegRad;
float cos = (float)Math.Cos(rotation), sin = (float)Math.Sin(rotation);
float za = (pa * cos + pb * sin) / skeleton.scaleX;
@ -252,8 +257,7 @@ namespace Spine {
za *= s;
zc *= s;
s = (float)Math.Sqrt(za * za + zc * zc);
if (data.transformMode == TransformMode.NoScale
&& (pa * pd - pb * pc < 0) != (skeleton.scaleX < 0 != skeleton.scaleY < 0)) s = -s;
if (inherit == Inherit.NoScale && (pa * pd - pb * pc < 0) != (skeleton.scaleX < 0 != skeleton.scaleY < 0)) s = -s;
rotation = MathUtils.PI / 2 + MathUtils.Atan2(zc, za);
float zb = (float)Math.Cos(rotation) * s;
float zd = (float)Math.Sin(rotation) * s;
@ -286,6 +290,7 @@ namespace Spine {
scaleY = data.scaleY;
shearX = data.shearX;
shearY = data.shearY;
inherit = data.inherit;
}
/// <summary>
@ -320,14 +325,14 @@ namespace Spine {
ay = (dy * id - dx * ic);
float ra, rb, rc, rd;
if (data.transformMode == TransformMode.OnlyTranslation) {
if (inherit == Inherit.OnlyTranslation) {
ra = a;
rb = b;
rc = c;
rd = d;
} else {
switch (data.transformMode) {
case TransformMode.NoRotationOrReflection: {
switch (inherit) {
case Inherit.NoRotationOrReflection: {
float s = Math.Abs(pa * pd - pb * pc) / (pa * pa + pc * pc);
float sa = pa / skeleton.scaleX;
float sc = pc / skeleton.scaleY;
@ -338,8 +343,8 @@ namespace Spine {
ib = pb * pid;
break;
}
case TransformMode.NoScale:
case TransformMode.NoScaleOrReflection: {
case Inherit.NoScale:
case Inherit.NoScaleOrReflection: {
float r = rotation * MathUtils.DegRad, cos = (float)Math.Cos(r), sin = (float)Math.Sin(r);
pa = (pa * cos + pb * sin) / skeleton.scaleX;
pc = (pc * cos + pd * sin) / skeleton.scaleY;
@ -348,7 +353,7 @@ namespace Spine {
pa *= s;
pc *= s;
s = (float)Math.Sqrt(pa * pa + pc * pc);
if (data.transformMode == TransformMode.NoScale && pid < 0 != (skeleton.scaleX < 0 != skeleton.scaleY < 0)) s = -s;
if (inherit == Inherit.NoScale && pid < 0 != (skeleton.scaleX < 0 != skeleton.scaleY < 0)) s = -s;
r = MathUtils.PI / 2 + MathUtils.Atan2(pc, pa);
pb = (float)Math.Cos(r) * s;
pd = (float)Math.Sin(r) * s;

View File

@ -36,7 +36,7 @@ namespace Spine {
internal BoneData parent;
internal float length;
internal float x, y, rotation, scaleX = 1, scaleY = 1, shearX, shearY;
internal TransformMode transformMode = TransformMode.Normal;
internal Inherit inherit = Inherit.Normal;
internal bool skinRequired;
/// <summary>The index of the bone in Skeleton.Bones</summary>
@ -71,8 +71,8 @@ namespace Spine {
/// <summary>Local shearY.</summary>
public float ShearY { get { return shearY; } set { shearY = value; } }
/// <summary>The transform mode for how parent world transforms affect this bone.</summary>
public TransformMode TransformMode { get { return transformMode; } set { transformMode = value; } }
/// <summary>Determines how parent world transforms affect this bone.</summary>
public Inherit Inherit { get { return inherit; } set { inherit = value; } }
/// <summary>When true, <see cref="Skeleton.UpdateWorldTransform(Skeleton.Physics)"/> only updates this bone if the <see cref="Skeleton.Skin"/> contains
/// this bone.</summary>
@ -93,13 +93,21 @@ namespace Spine {
}
}
[Flags]
public enum TransformMode {
//0000 0 Flip Scale Rotation
Normal = 0, // 0000
OnlyTranslation = 7, // 0111
NoRotationOrReflection = 1, // 0001
NoScale = 2, // 0010
NoScaleOrReflection = 6, // 0110
public enum Inherit {
Normal,
OnlyTranslation,
NoRotationOrReflection,
NoScale,
NoScaleOrReflection
}
public class InheritEnum {
public static readonly Inherit[] Values = {
Inherit.Normal,
Inherit.OnlyTranslation,
Inherit.NoRotationOrReflection,
Inherit.NoScale,
Inherit.NoScaleOrReflection
};
}
}

View File

@ -175,12 +175,12 @@ namespace Spine {
float rotationIK = -bone.ashearX - bone.arotation;
float tx = 0, ty = 0;
switch (bone.data.transformMode) {
case TransformMode.OnlyTranslation:
switch (bone.inherit) {
case Inherit.OnlyTranslation:
tx = (targetX - bone.worldX) * Math.Sign(bone.skeleton.ScaleX);
ty = (targetY - bone.worldY) * Math.Sign(bone.skeleton.ScaleY);
break;
case TransformMode.NoRotationOrReflection: {
case Inherit.NoRotationOrReflection: {
float s = Math.Abs(pa * pd - pb * pc) / Math.Max(0.0001f, pa * pa + pc * pc);
float sa = pa / bone.skeleton.scaleX;
float sc = pc / bone.skeleton.scaleY;
@ -212,9 +212,9 @@ namespace Spine {
float sx = bone.ascaleX, sy = bone.ascaleY;
if (compress || stretch) {
switch (bone.data.transformMode) {
case TransformMode.NoScale:
case TransformMode.NoScaleOrReflection:
switch (bone.inherit) {
case Inherit.NoScale:
case Inherit.NoScaleOrReflection:
tx = targetX - bone.worldX;
ty = targetY - bone.worldY;
break;
@ -238,6 +238,7 @@ namespace Spine {
float softness, float alpha) {
if (parent == null) throw new ArgumentNullException("parent", "parent cannot be null.");
if (child == null) throw new ArgumentNullException("child", "child cannot be null.");
if (parent.inherit != Inherit.Normal || child.inherit != Inherit.Normal) return;
float px = parent.ax, py = parent.ay, psx = parent.ascaleX, psy = parent.ascaleY, sx = psx, sy = psy, csx = child.ascaleX;
int os1, os2, s2;
if (psx < 0) {

View File

@ -53,6 +53,7 @@ namespace Spine {
public const int BONE_SHEAR = 7;
public const int BONE_SHEARX = 8;
public const int BONE_SHEARY = 9;
public const int BONE_INHERIT = 10;
public const int SLOT_ATTACHMENT = 0;
public const int SLOT_RGBA = 1;
@ -118,14 +119,6 @@ namespace Spine {
}
#endif // WINDOWS_STOREAPP
public static readonly TransformMode[] TransformModeValues = {
TransformMode.Normal,
TransformMode.OnlyTranslation,
TransformMode.NoRotationOrReflection,
TransformMode.NoScale,
TransformMode.NoScaleOrReflection
};
/// <summary>Returns the version string of binary skeleton data.</summary>
public static string GetVersionString (Stream file) {
if (file == null) throw new ArgumentNullException("file");
@ -187,7 +180,7 @@ namespace Spine {
data.shearX = input.ReadFloat();
data.shearY = input.ReadFloat();
data.Length = input.ReadFloat() * scale;
data.transformMode = TransformModeValues[input.ReadInt(true)];
data.inherit = InheritEnum.Values[input.ReadInt(true)];
data.skinRequired = input.ReadBoolean();
if (nonessential) { // discard non-essential data
input.ReadInt(); // Color.rgba8888ToColor(data.color, input.readInt());
@ -844,7 +837,15 @@ namespace Spine {
for (int i = 0, n = input.ReadInt(true); i < n; i++) {
int boneIndex = input.ReadInt(true);
for (int ii = 0, nn = input.ReadInt(true); ii < nn; ii++) {
int type = input.ReadUByte(), frameCount = input.ReadInt(true), bezierCount = input.ReadInt(true);
int type = input.ReadUByte(), frameCount = input.ReadInt(true);
if (type == BONE_INHERIT) {
InheritTimeline timeline = new InheritTimeline(frameCount, boneIndex);
for (int frame = 0; frame < frameCount; frame++)
timeline.SetFrame(frame, input.ReadFloat(), InheritEnum.Values[input.ReadUByte()]);
timelines.Add(timeline);
continue;
}
int bezierCount = input.ReadInt(true);
switch (type) {
case BONE_ROTATE:
ReadTimeline(input, timelines, new RotateTimeline(frameCount, bezierCount, boneIndex), 1);

View File

@ -133,8 +133,8 @@ namespace Spine {
data.shearX = GetFloat(boneMap, "shearX", 0);
data.shearY = GetFloat(boneMap, "shearY", 0);
string tm = GetString(boneMap, "transform", TransformMode.Normal.ToString());
data.transformMode = (TransformMode)Enum.Parse(typeof(TransformMode), tm, true);
string inheritString = GetString(boneMap, "inherit", Inherit.Normal.ToString());
data.inherit = (Inherit)Enum.Parse(typeof(Inherit), inheritString, true);
data.skinRequired = GetBoolean(boneMap, "skin", false);
skeletonData.bones.Add(data);
@ -874,7 +874,19 @@ namespace Spine {
timelines.Add(ReadTimeline(ref keyMapEnumerator, new ShearXTimeline(frames, frames, boneIndex), 0, 1));
else if (timelineName == "sheary")
timelines.Add(ReadTimeline(ref keyMapEnumerator, new ShearYTimeline(frames, frames, boneIndex), 0, 1));
else
else if (timelineName == "inherit") {
InheritTimeline timeline = new InheritTimeline(frames, boneIndex);
for (int frame = 0; ; frame++) {
Dictionary<string, object> keyMap = (Dictionary<string, Object>)keyMapEnumerator.Current;
float time = GetFloat(keyMap, "time", 0);
Inherit inherit = (Inherit)Enum.Parse(typeof(Inherit), GetString(keyMap, "inherit", Inherit.Normal.ToString()), true);
timeline.SetFrame(frame, time, inherit);
if (!keyMapEnumerator.MoveNext()) {
break;
}
}
timelines.Add(timeline);
} else
throw new Exception("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")");
}
}

View File

@ -329,13 +329,13 @@ namespace Spine.Unity.Editor {
boneTransform.parent = parentTransform;
boneTransform.localPosition = new Vector3(boneData.X, boneData.Y, 0);
TransformMode tm = boneData.TransformMode;
if (tm.InheritsRotation())
Inherit inherit = boneData.Inherit;
if (inherit.InheritsRotation())
boneTransform.localRotation = Quaternion.Euler(0, 0, boneData.Rotation);
else
boneTransform.rotation = Quaternion.Euler(0, 0, boneData.Rotation);
if (tm.InheritsScale())
if (inherit.InheritsScale())
boneTransform.localScale = new Vector3(boneData.ScaleX, boneData.ScaleY, 1);
}
@ -774,7 +774,7 @@ namespace Spine.Unity.Editor {
}
foreach (Bone b in skeleton.Bones) {
if (!b.Data.TransformMode.InheritsRotation()) {
if (!b.Data.Inherit.InheritsRotation()) {
int index = b.Data.Index;
if (ignoreRotateTimelineIndexes.Contains(index) == false) {
ignoreRotateTimelineIndexes.Add(index);
@ -832,7 +832,7 @@ namespace Spine.Unity.Editor {
static void BakeBoneConstraints (Bone bone, Spine.Animation animation, AnimationClip clip) {
Skeleton skeleton = bone.Skeleton;
bool inheritRotation = bone.Data.TransformMode.InheritsRotation();
bool inheritRotation = bone.Data.Inherit.InheritsRotation();
animation.Apply(skeleton, 0, 0, false, null, 1f, MixBlend.Setup, MixDirection.In);
skeleton.UpdateWorldTransform(Skeleton.Physics.Update);

View File

@ -134,7 +134,7 @@ namespace Spine.Unity {
zPosition ? 0 : thisTransform.localPosition.z);
if (rotation) {
if (bone.Data.TransformMode.InheritsRotation()) {
if (bone.Data.Inherit.InheritsRotation()) {
thisTransform.localRotation = Quaternion.Euler(0, 0, bone.Rotation);
} else {
Vector3 euler = skeletonTransform.rotation.eulerAngles;
@ -154,7 +154,7 @@ namespace Spine.Unity {
zPosition ? 0 : thisTransform.localPosition.z);
if (rotation) {
if (bone.Data.TransformMode.InheritsRotation()) {
if (bone.Data.Inherit.InheritsRotation()) {
thisTransform.localRotation = Quaternion.Euler(0, 0, bone.AppliedRotation);
} else {
Vector3 euler = skeletonTransform.rotation.eulerAngles;
@ -222,7 +222,7 @@ namespace Spine.Unity {
}
public static bool BoneTransformModeIncompatible (Bone bone) {
return !bone.Data.TransformMode.InheritsScale();
return !bone.Data.Inherit.InheritsScale();
}
public void AddBoundingBox (string skinName, string slotName, string attachmentName) {

View File

@ -325,8 +325,8 @@ namespace Spine {
result.x = pa * boneData.X + pb * boneData.Y + parentMatrix.x;
result.y = pc * boneData.X + pd * boneData.Y + parentMatrix.y;
switch (boneData.TransformMode) {
case TransformMode.Normal: {
switch (boneData.Inherit) {
case Inherit.Normal: {
float rotationY = boneData.Rotation + 90 + boneData.ShearY;
float la = MathUtils.CosDeg(boneData.Rotation + boneData.ShearX) * boneData.ScaleX;
float lb = MathUtils.CosDeg(rotationY) * boneData.ScaleY;
@ -338,7 +338,7 @@ namespace Spine {
result.d = pc * lb + pd * ld;
break;
}
case TransformMode.OnlyTranslation: {
case Inherit.OnlyTranslation: {
float rotationY = boneData.Rotation + 90 + boneData.ShearY;
result.a = MathUtils.CosDeg(boneData.Rotation + boneData.ShearX) * boneData.ScaleX;
result.b = MathUtils.CosDeg(rotationY) * boneData.ScaleY;
@ -346,7 +346,7 @@ namespace Spine {
result.d = MathUtils.SinDeg(rotationY) * boneData.ScaleY;
break;
}
case TransformMode.NoRotationOrReflection: {
case Inherit.NoRotationOrReflection: {
float s = pa * pa + pc * pc, prx;
if (s > 0.0001f) {
s = Math.Abs(pa * pd - pb * pc) / s;
@ -370,8 +370,8 @@ namespace Spine {
result.d = pc * lb + pd * ld;
break;
}
case TransformMode.NoScale:
case TransformMode.NoScaleOrReflection: {
case Inherit.NoScale:
case Inherit.NoScaleOrReflection: {
float cos = MathUtils.CosDeg(boneData.Rotation), sin = MathUtils.SinDeg(boneData.Rotation);
float za = pa * cos + pb * sin;
float zc = pc * cos + pd * sin;
@ -388,7 +388,7 @@ namespace Spine {
float lb = MathUtils.CosDeg(90 + boneData.ShearY) * boneData.ScaleY;
float lc = MathUtils.SinDeg(boneData.ShearX) * boneData.ScaleX;
float ld = MathUtils.SinDeg(90 + boneData.ShearY) * boneData.ScaleY;
if (boneData.TransformMode != TransformMode.NoScaleOrReflection ? pa * pd - pb * pc < 0 : false) {
if (boneData.Inherit != Inherit.NoScaleOrReflection ? pa * pd - pb * pc < 0 : false) {
zb = -zb;
zd = -zd;
}
@ -446,15 +446,13 @@ namespace Spine {
return va.Bones != null && va.Bones.Length > 0;
}
#region Transform Modes
public static bool InheritsRotation (this TransformMode mode) {
const int RotationBit = 0;
return ((int)mode & (1U << RotationBit)) == 0;
#region Inherit Modes
public static bool InheritsRotation (this Inherit mode) {
return mode == Inherit.Normal || mode == Inherit.NoScale || mode == Inherit.NoScaleOrReflection;
}
public static bool InheritsScale (this TransformMode mode) {
const int ScaleBit = 1;
return ((int)mode & (1U << ScaleBit)) == 0;
public static bool InheritsScale (this Inherit mode) {
return mode == Inherit.Normal || mode == Inherit.NoRotationOrReflection;
}
#endregion
}