增加GetBounds获取最大包围盒方法
This commit is contained in:
@@ -206,49 +206,53 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
|
|
||||||
protected override RectangleF getCurrentBounds()
|
protected override RectangleF getCurrentBounds()
|
||||||
{
|
{
|
||||||
float[] temp = new float[8];
|
skeleton.GetBounds(out var x, out var y, out var w, out var h);
|
||||||
var drawOrderItems = skeleton.DrawOrder;
|
return new RectangleF(x, y, w, h);
|
||||||
float minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue;
|
|
||||||
for (int i = 0, n = skeleton.DrawOrder.Count; i < n; i++)
|
|
||||||
{
|
|
||||||
Slot slot = drawOrderItems[i];
|
|
||||||
int verticesLength = 0;
|
|
||||||
float[] vertices = null;
|
|
||||||
Attachment attachment = slot.Attachment;
|
|
||||||
var regionAttachment = attachment as RegionAttachment;
|
|
||||||
if (regionAttachment != null)
|
|
||||||
{
|
|
||||||
verticesLength = 8;
|
|
||||||
vertices = temp;
|
|
||||||
if (vertices.Length < 8) vertices = temp = new float[8];
|
|
||||||
regionAttachment.ComputeWorldVertices(slot.Bone, temp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var meshAttachment = attachment as MeshAttachment;
|
|
||||||
if (meshAttachment != null)
|
|
||||||
{
|
|
||||||
MeshAttachment mesh = meshAttachment;
|
|
||||||
verticesLength = mesh.Vertices.Length;
|
|
||||||
vertices = temp;
|
|
||||||
if (vertices.Length < verticesLength) vertices = temp = new float[verticesLength];
|
|
||||||
mesh.ComputeWorldVertices(slot, temp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertices != null)
|
protected override RectangleF getBounds()
|
||||||
{
|
{
|
||||||
for (int ii = 0; ii < verticesLength; ii += 2)
|
// 初始化临时对象
|
||||||
|
var maxDuration = 0f;
|
||||||
|
var tmpSkeleton = new Skeleton(skeletonData) { Skin = new(Guid.NewGuid().ToString()) };
|
||||||
|
var tmpAnimationState = new AnimationState(animationStateData);
|
||||||
|
tmpSkeleton.FlipX = skeleton.FlipX;
|
||||||
|
tmpSkeleton.FlipY = skeleton.FlipY;
|
||||||
|
tmpSkeleton.X = skeleton.X;
|
||||||
|
tmpSkeleton.Y = skeleton.Y;
|
||||||
|
foreach (var name in loadedSkins)
|
||||||
{
|
{
|
||||||
float vx = vertices[ii], vy = vertices[ii + 1];
|
foreach (var (k, v) in skeletonData.FindSkin(name).Attachments)
|
||||||
minX = Math.Min(minX, vx);
|
tmpSkeleton.Skin.AddAttachment(k.Key, k.Value, v);
|
||||||
minY = Math.Min(minY, vy);
|
|
||||||
maxX = Math.Max(maxX, vx);
|
|
||||||
maxY = Math.Max(maxY, vy);
|
|
||||||
}
|
}
|
||||||
|
foreach (var tr in animationState.Tracks.Select((_, i) => i).Where(i => animationState.Tracks[i] is not null))
|
||||||
|
{
|
||||||
|
var ani = animationState.GetCurrent(tr).Animation;
|
||||||
|
tmpAnimationState.SetAnimation(tr, ani, true);
|
||||||
|
if (ani.Duration > maxDuration) maxDuration = ani.Duration;
|
||||||
}
|
}
|
||||||
|
tmpSkeleton.SetSlotsToSetupPose();
|
||||||
|
tmpAnimationState.Update(0);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
tmpSkeleton.Update(0);
|
||||||
|
tmpSkeleton.UpdateWorldTransform();
|
||||||
|
|
||||||
|
// 切成 100 帧获取边界最大值
|
||||||
|
var bounds = getCurrentBounds();
|
||||||
|
for (float tick = 0, delta = maxDuration / 100; tick < maxDuration; tick += delta)
|
||||||
|
{
|
||||||
|
tmpSkeleton.GetBounds(out var x, out var y, out var w, out var h);
|
||||||
|
if (x < bounds.X) bounds.X = x;
|
||||||
|
if (y < bounds.Y) bounds.Y = y;
|
||||||
|
if (w > bounds.Width) bounds.Width = w;
|
||||||
|
if (h > bounds.Height) bounds.Height = h;
|
||||||
|
tmpAnimationState.Update(delta);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
tmpSkeleton.Update(delta);
|
||||||
|
tmpSkeleton.UpdateWorldTransform();
|
||||||
}
|
}
|
||||||
return new RectangleF(minX, minY, maxX - minX, maxY - minY);
|
|
||||||
|
return bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void update(float delta)
|
protected override void update(float delta)
|
||||||
|
|||||||
@@ -210,6 +210,52 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
return new RectangleF(x, y, w, h);
|
return new RectangleF(x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override RectangleF getBounds()
|
||||||
|
{
|
||||||
|
// 初始化临时对象
|
||||||
|
var maxDuration = 0f;
|
||||||
|
var tmpSkeleton = new Skeleton(skeletonData) { Skin = new(Guid.NewGuid().ToString()) };
|
||||||
|
var tmpAnimationState = new AnimationState(animationStateData);
|
||||||
|
tmpSkeleton.FlipX = skeleton.FlipX;
|
||||||
|
tmpSkeleton.FlipY = skeleton.FlipY;
|
||||||
|
tmpSkeleton.X = skeleton.X;
|
||||||
|
tmpSkeleton.Y = skeleton.Y;
|
||||||
|
foreach (var name in loadedSkins)
|
||||||
|
{
|
||||||
|
foreach (var (k, v) in skeletonData.FindSkin(name).Attachments)
|
||||||
|
tmpSkeleton.Skin.AddAttachment(k.slotIndex, k.name, v);
|
||||||
|
}
|
||||||
|
foreach (var tr in animationState.Tracks.Select((_, i) => i).Where(i => animationState.Tracks.Items[i] is not null))
|
||||||
|
{
|
||||||
|
var ani = animationState.GetCurrent(tr).Animation;
|
||||||
|
tmpAnimationState.SetAnimation(tr, ani, true);
|
||||||
|
if (ani.Duration > maxDuration) maxDuration = ani.Duration;
|
||||||
|
}
|
||||||
|
tmpSkeleton.SetSlotsToSetupPose();
|
||||||
|
tmpAnimationState.Update(0);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
tmpSkeleton.Update(0);
|
||||||
|
tmpSkeleton.UpdateWorldTransform();
|
||||||
|
|
||||||
|
// 切成 100 帧获取边界最大值
|
||||||
|
var bounds = getCurrentBounds();
|
||||||
|
float[] _ = [];
|
||||||
|
for (float tick = 0, delta = maxDuration / 100; tick < maxDuration; tick += delta)
|
||||||
|
{
|
||||||
|
tmpSkeleton.GetBounds(out var x, out var y, out var w, out var h, ref _);
|
||||||
|
if (x < bounds.X) bounds.X = x;
|
||||||
|
if (y < bounds.Y) bounds.Y = y;
|
||||||
|
if (w > bounds.Width) bounds.Width = w;
|
||||||
|
if (h > bounds.Height) bounds.Height = h;
|
||||||
|
tmpAnimationState.Update(delta);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
tmpSkeleton.Update(delta);
|
||||||
|
tmpSkeleton.UpdateWorldTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void update(float delta)
|
protected override void update(float delta)
|
||||||
{
|
{
|
||||||
animationState.Update(delta);
|
animationState.Update(delta);
|
||||||
@@ -218,18 +264,6 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
skeleton.UpdateWorldTransform();
|
skeleton.UpdateWorldTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SFML.Graphics.BlendMode GetSFMLBlendMode(BlendMode spineBlendMode)
|
|
||||||
{
|
|
||||||
return spineBlendMode switch
|
|
||||||
{
|
|
||||||
BlendMode.Normal => SFMLBlendMode.NormalPma,
|
|
||||||
BlendMode.Additive => SFMLBlendMode.AdditivePma,
|
|
||||||
BlendMode.Multiply => SFMLBlendMode.MultiplyPma,
|
|
||||||
BlendMode.Screen => SFMLBlendMode.ScreenPma,
|
|
||||||
_ => throw new NotImplementedException($"{spineBlendMode}"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
|
protected override void draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
|
||||||
{
|
{
|
||||||
triangleVertices.Clear();
|
triangleVertices.Clear();
|
||||||
|
|||||||
@@ -181,6 +181,52 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
return new RectangleF(x, y, w, h);
|
return new RectangleF(x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override RectangleF getBounds()
|
||||||
|
{
|
||||||
|
// 初始化临时对象
|
||||||
|
var maxDuration = 0f;
|
||||||
|
var tmpSkeleton = new Skeleton(skeletonData) { Skin = new(Guid.NewGuid().ToString()) };
|
||||||
|
var tmpAnimationState = new AnimationState(animationStateData);
|
||||||
|
tmpSkeleton.ScaleX = skeleton.ScaleX;
|
||||||
|
tmpSkeleton.ScaleY = skeleton.ScaleY;
|
||||||
|
tmpSkeleton.X = skeleton.X;
|
||||||
|
tmpSkeleton.Y = skeleton.Y;
|
||||||
|
foreach (var name in loadedSkins)
|
||||||
|
{
|
||||||
|
foreach (var (k, v) in skeletonData.FindSkin(name).Attachments)
|
||||||
|
tmpSkeleton.Skin.AddAttachment(k.slotIndex, k.name, v);
|
||||||
|
}
|
||||||
|
foreach (var tr in animationState.Tracks.Select((_, i) => i).Where(i => animationState.Tracks.Items[i] is not null))
|
||||||
|
{
|
||||||
|
var ani = animationState.GetCurrent(tr).Animation;
|
||||||
|
tmpAnimationState.SetAnimation(tr, ani, true);
|
||||||
|
if (ani.Duration > maxDuration) maxDuration = ani.Duration;
|
||||||
|
}
|
||||||
|
tmpSkeleton.SetSlotsToSetupPose();
|
||||||
|
tmpAnimationState.Update(0);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
tmpSkeleton.Update(0);
|
||||||
|
tmpSkeleton.UpdateWorldTransform();
|
||||||
|
|
||||||
|
// 切成 100 帧获取边界最大值
|
||||||
|
var bounds = getCurrentBounds();
|
||||||
|
float[] _ = [];
|
||||||
|
for (float tick = 0, delta = maxDuration / 100; tick < maxDuration; tick += delta)
|
||||||
|
{
|
||||||
|
tmpSkeleton.GetBounds(out var x, out var y, out var w, out var h, ref _);
|
||||||
|
if (x < bounds.X) bounds.X = x;
|
||||||
|
if (y < bounds.Y) bounds.Y = y;
|
||||||
|
if (w > bounds.Width) bounds.Width = w;
|
||||||
|
if (h > bounds.Height) bounds.Height = h;
|
||||||
|
tmpAnimationState.Update(delta);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
tmpSkeleton.Update(delta);
|
||||||
|
tmpSkeleton.UpdateWorldTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void update(float delta)
|
protected override void update(float delta)
|
||||||
{
|
{
|
||||||
animationState.Update(delta);
|
animationState.Update(delta);
|
||||||
@@ -189,18 +235,6 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
skeleton.UpdateWorldTransform();
|
skeleton.UpdateWorldTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SFML.Graphics.BlendMode GetSFMLBlendMode(BlendMode spineBlendMode)
|
|
||||||
{
|
|
||||||
return spineBlendMode switch
|
|
||||||
{
|
|
||||||
BlendMode.Normal => SFMLBlendMode.NormalPma,
|
|
||||||
BlendMode.Additive => SFMLBlendMode.AdditivePma,
|
|
||||||
BlendMode.Multiply => SFMLBlendMode.MultiplyPma,
|
|
||||||
BlendMode.Screen => SFMLBlendMode.ScreenPma,
|
|
||||||
_ => throw new NotImplementedException($"{spineBlendMode}"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
|
protected override void draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
|
||||||
{
|
{
|
||||||
triangleVertices.Clear();
|
triangleVertices.Clear();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Linq;
|
||||||
using SpineRuntime38;
|
using SpineRuntime38;
|
||||||
using SpineRuntime38.Attachments;
|
using SpineRuntime38.Attachments;
|
||||||
using SpineViewer.Utils;
|
using SpineViewer.Utils;
|
||||||
@@ -14,7 +15,17 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
[SpineImplementation(SpineVersion.V38)]
|
[SpineImplementation(SpineVersion.V38)]
|
||||||
internal class SpineObject38 : Spine.SpineObject
|
internal class SpineObject38 : Spine.SpineObject
|
||||||
{
|
{
|
||||||
private static readonly Animation EmptyAnimation = new(EMPTY_ANIMATION, [], 0);
|
private static SFML.Graphics.BlendMode GetSFMLBlendMode(BlendMode spineBlendMode)
|
||||||
|
{
|
||||||
|
return spineBlendMode switch
|
||||||
|
{
|
||||||
|
BlendMode.Normal => SFMLBlendMode.NormalPma,
|
||||||
|
BlendMode.Additive => SFMLBlendMode.AdditivePma,
|
||||||
|
BlendMode.Multiply => SFMLBlendMode.MultiplyPma,
|
||||||
|
BlendMode.Screen => SFMLBlendMode.ScreenPma,
|
||||||
|
_ => throw new NotImplementedException($"{spineBlendMode}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private class TextureLoader : SpineRuntime38.TextureLoader
|
private class TextureLoader : SpineRuntime38.TextureLoader
|
||||||
{
|
{
|
||||||
@@ -38,18 +49,19 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TextureLoader textureLoader = new();
|
private static readonly TextureLoader textureLoader = new();
|
||||||
|
private static readonly Animation EmptyAnimation = new(EMPTY_ANIMATION, [], 0);
|
||||||
|
|
||||||
private Atlas atlas;
|
private readonly Atlas atlas;
|
||||||
private SkeletonBinary? skeletonBinary;
|
private readonly SkeletonBinary? skeletonBinary;
|
||||||
private SkeletonJson? skeletonJson;
|
private readonly SkeletonJson? skeletonJson;
|
||||||
private SkeletonData skeletonData;
|
private readonly SkeletonData skeletonData;
|
||||||
private AnimationStateData animationStateData;
|
private readonly AnimationStateData animationStateData;
|
||||||
|
|
||||||
private Skeleton skeleton;
|
private readonly Skeleton skeleton;
|
||||||
private AnimationState animationState;
|
private readonly AnimationState animationState;
|
||||||
|
|
||||||
private SkeletonClipping clipping = new();
|
private readonly SkeletonClipping clipping = new();
|
||||||
|
|
||||||
public SpineObject38(string skelPath, string atlasPath) : base(skelPath, atlasPath)
|
public SpineObject38(string skelPath, string atlasPath) : base(skelPath, atlasPath)
|
||||||
{
|
{
|
||||||
@@ -174,6 +186,48 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
return new RectangleF(x, y, w, h);
|
return new RectangleF(x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override RectangleF getBounds()
|
||||||
|
{
|
||||||
|
// 初始化临时对象
|
||||||
|
var maxDuration = 0f;
|
||||||
|
var tmpSkeleton = new Skeleton(skeletonData) { Skin = new(Guid.NewGuid().ToString()) };
|
||||||
|
var tmpAnimationState = new AnimationState(animationStateData);
|
||||||
|
tmpSkeleton.ScaleX = skeleton.ScaleX;
|
||||||
|
tmpSkeleton.ScaleY = skeleton.ScaleY;
|
||||||
|
tmpSkeleton.X = skeleton.X;
|
||||||
|
tmpSkeleton.Y = skeleton.Y;
|
||||||
|
foreach (var sk in loadedSkins) tmpSkeleton.Skin.AddSkin(skeletonData.FindSkin(sk));
|
||||||
|
foreach (var tr in animationState.Tracks.Select((_, i) => i).Where(i => animationState.Tracks.Items[i] is not null))
|
||||||
|
{
|
||||||
|
var ani = animationState.GetCurrent(tr).Animation;
|
||||||
|
tmpAnimationState.SetAnimation(tr, ani, true);
|
||||||
|
if (ani.Duration > maxDuration) maxDuration = ani.Duration;
|
||||||
|
}
|
||||||
|
tmpSkeleton.SetSlotsToSetupPose();
|
||||||
|
tmpAnimationState.Update(0);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
tmpSkeleton.Update(0);
|
||||||
|
tmpSkeleton.UpdateWorldTransform();
|
||||||
|
|
||||||
|
// 切成 100 帧获取边界最大值
|
||||||
|
var bounds = getCurrentBounds();
|
||||||
|
float[] _ = [];
|
||||||
|
for (float tick = 0, delta = maxDuration / 100; tick < maxDuration; tick += delta)
|
||||||
|
{
|
||||||
|
tmpSkeleton.GetBounds(out var x, out var y, out var w, out var h, ref _);
|
||||||
|
if (x < bounds.X) bounds.X = x;
|
||||||
|
if (y < bounds.Y) bounds.Y = y;
|
||||||
|
if (w > bounds.Width) bounds.Width = w;
|
||||||
|
if (h > bounds.Height) bounds.Height = h;
|
||||||
|
tmpAnimationState.Update(delta);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
tmpSkeleton.Update(delta);
|
||||||
|
tmpSkeleton.UpdateWorldTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void update(float delta)
|
protected override void update(float delta)
|
||||||
{
|
{
|
||||||
animationState.Update(delta);
|
animationState.Update(delta);
|
||||||
@@ -182,18 +236,6 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
skeleton.UpdateWorldTransform();
|
skeleton.UpdateWorldTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SFML.Graphics.BlendMode GetSFMLBlendMode(BlendMode spineBlendMode)
|
|
||||||
{
|
|
||||||
return spineBlendMode switch
|
|
||||||
{
|
|
||||||
BlendMode.Normal => SFMLBlendMode.NormalPma,
|
|
||||||
BlendMode.Additive => SFMLBlendMode.AdditivePma,
|
|
||||||
BlendMode.Multiply => SFMLBlendMode.MultiplyPma,
|
|
||||||
BlendMode.Screen => SFMLBlendMode.ScreenPma,
|
|
||||||
_ => throw new NotImplementedException($"{spineBlendMode}"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
|
protected override void draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
|
||||||
{
|
{
|
||||||
triangleVertices.Clear();
|
triangleVertices.Clear();
|
||||||
|
|||||||
@@ -13,7 +13,17 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
[SpineImplementation(SpineVersion.V40)]
|
[SpineImplementation(SpineVersion.V40)]
|
||||||
internal class SpineObject40 : Spine.SpineObject
|
internal class SpineObject40 : Spine.SpineObject
|
||||||
{
|
{
|
||||||
private static readonly Animation EmptyAnimation = new(EMPTY_ANIMATION, [], 0);
|
private static SFML.Graphics.BlendMode GetSFMLBlendMode(BlendMode spineBlendMode)
|
||||||
|
{
|
||||||
|
return spineBlendMode switch
|
||||||
|
{
|
||||||
|
BlendMode.Normal => SFMLBlendMode.NormalPma,
|
||||||
|
BlendMode.Additive => SFMLBlendMode.AdditivePma,
|
||||||
|
BlendMode.Multiply => SFMLBlendMode.MultiplyPma,
|
||||||
|
BlendMode.Screen => SFMLBlendMode.ScreenPma,
|
||||||
|
_ => throw new NotImplementedException($"{spineBlendMode}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private class TextureLoader : SpineRuntime40.TextureLoader
|
private class TextureLoader : SpineRuntime40.TextureLoader
|
||||||
{
|
{
|
||||||
@@ -34,18 +44,19 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TextureLoader textureLoader = new();
|
private static readonly TextureLoader textureLoader = new();
|
||||||
|
private static readonly Animation EmptyAnimation = new(EMPTY_ANIMATION, [], 0);
|
||||||
|
|
||||||
private Atlas atlas;
|
private readonly Atlas atlas;
|
||||||
private SkeletonBinary? skeletonBinary;
|
private readonly SkeletonBinary? skeletonBinary;
|
||||||
private SkeletonJson? skeletonJson;
|
private readonly SkeletonJson? skeletonJson;
|
||||||
private SkeletonData skeletonData;
|
private readonly SkeletonData skeletonData;
|
||||||
private AnimationStateData animationStateData;
|
private readonly AnimationStateData animationStateData;
|
||||||
|
|
||||||
private Skeleton skeleton;
|
private readonly Skeleton skeleton;
|
||||||
private AnimationState animationState;
|
private readonly AnimationState animationState;
|
||||||
|
|
||||||
private SkeletonClipping clipping = new();
|
private readonly SkeletonClipping clipping = new();
|
||||||
|
|
||||||
public SpineObject40(string skelPath, string atlasPath) : base(skelPath, atlasPath)
|
public SpineObject40(string skelPath, string atlasPath) : base(skelPath, atlasPath)
|
||||||
{
|
{
|
||||||
@@ -170,6 +181,48 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
return new RectangleF(x, y, w, h);
|
return new RectangleF(x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override RectangleF getBounds()
|
||||||
|
{
|
||||||
|
// 初始化临时对象
|
||||||
|
var maxDuration = 0f;
|
||||||
|
var tmpSkeleton = new Skeleton(skeletonData) { Skin = new(Guid.NewGuid().ToString()) };
|
||||||
|
var tmpAnimationState = new AnimationState(animationStateData);
|
||||||
|
tmpSkeleton.ScaleX = skeleton.ScaleX;
|
||||||
|
tmpSkeleton.ScaleY = skeleton.ScaleY;
|
||||||
|
tmpSkeleton.X = skeleton.X;
|
||||||
|
tmpSkeleton.Y = skeleton.Y;
|
||||||
|
foreach (var sk in loadedSkins) tmpSkeleton.Skin.AddSkin(skeletonData.FindSkin(sk));
|
||||||
|
foreach (var tr in animationState.Tracks.Select((_, i) => i).Where(i => animationState.Tracks.Items[i] is not null))
|
||||||
|
{
|
||||||
|
var ani = animationState.GetCurrent(tr).Animation;
|
||||||
|
tmpAnimationState.SetAnimation(tr, ani, true);
|
||||||
|
if (ani.Duration > maxDuration) maxDuration = ani.Duration;
|
||||||
|
}
|
||||||
|
tmpSkeleton.SetSlotsToSetupPose();
|
||||||
|
tmpAnimationState.Update(0);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
tmpSkeleton.Update(0);
|
||||||
|
tmpSkeleton.UpdateWorldTransform();
|
||||||
|
|
||||||
|
// 切成 100 帧获取边界最大值
|
||||||
|
var bounds = getCurrentBounds();
|
||||||
|
float[] _ = [];
|
||||||
|
for (float tick = 0, delta = maxDuration / 100; tick < maxDuration; tick += delta)
|
||||||
|
{
|
||||||
|
tmpSkeleton.GetBounds(out var x, out var y, out var w, out var h, ref _);
|
||||||
|
if (x < bounds.X) bounds.X = x;
|
||||||
|
if (y < bounds.Y) bounds.Y = y;
|
||||||
|
if (w > bounds.Width) bounds.Width = w;
|
||||||
|
if (h > bounds.Height) bounds.Height = h;
|
||||||
|
tmpAnimationState.Update(delta);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
tmpSkeleton.Update(delta);
|
||||||
|
tmpSkeleton.UpdateWorldTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void update(float delta)
|
protected override void update(float delta)
|
||||||
{
|
{
|
||||||
animationState.Update(delta);
|
animationState.Update(delta);
|
||||||
@@ -178,18 +231,6 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
skeleton.UpdateWorldTransform();
|
skeleton.UpdateWorldTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SFML.Graphics.BlendMode GetSFMLBlendMode(BlendMode spineBlendMode)
|
|
||||||
{
|
|
||||||
return spineBlendMode switch
|
|
||||||
{
|
|
||||||
BlendMode.Normal => SFMLBlendMode.NormalPma,
|
|
||||||
BlendMode.Additive => SFMLBlendMode.AdditivePma,
|
|
||||||
BlendMode.Multiply => SFMLBlendMode.MultiplyPma,
|
|
||||||
BlendMode.Screen => SFMLBlendMode.ScreenPma,
|
|
||||||
_ => throw new NotImplementedException($"{spineBlendMode}"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
|
protected override void draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
|
||||||
{
|
{
|
||||||
triangleVertices.Clear();
|
triangleVertices.Clear();
|
||||||
|
|||||||
@@ -13,7 +13,17 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
[SpineImplementation(SpineVersion.V41)]
|
[SpineImplementation(SpineVersion.V41)]
|
||||||
internal class SpineObject41 : Spine.SpineObject
|
internal class SpineObject41 : Spine.SpineObject
|
||||||
{
|
{
|
||||||
private static readonly Animation EmptyAnimation = new(EMPTY_ANIMATION, [], 0);
|
private static SFML.Graphics.BlendMode GetSFMLBlendMode(BlendMode spineBlendMode)
|
||||||
|
{
|
||||||
|
return spineBlendMode switch
|
||||||
|
{
|
||||||
|
BlendMode.Normal => SFMLBlendMode.NormalPma,
|
||||||
|
BlendMode.Additive => SFMLBlendMode.AdditivePma,
|
||||||
|
BlendMode.Multiply => SFMLBlendMode.MultiplyPma,
|
||||||
|
BlendMode.Screen => SFMLBlendMode.ScreenPma,
|
||||||
|
_ => throw new NotImplementedException($"{spineBlendMode}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private class TextureLoader : SpineRuntime41.TextureLoader
|
private class TextureLoader : SpineRuntime41.TextureLoader
|
||||||
{
|
{
|
||||||
@@ -35,17 +45,18 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static TextureLoader textureLoader = new();
|
private static TextureLoader textureLoader = new();
|
||||||
|
private static readonly Animation EmptyAnimation = new(EMPTY_ANIMATION, [], 0);
|
||||||
|
|
||||||
private Atlas atlas;
|
private readonly Atlas atlas;
|
||||||
private SkeletonBinary? skeletonBinary;
|
private readonly SkeletonBinary? skeletonBinary;
|
||||||
private SkeletonJson? skeletonJson;
|
private readonly SkeletonJson? skeletonJson;
|
||||||
private SkeletonData skeletonData;
|
private readonly SkeletonData skeletonData;
|
||||||
private AnimationStateData animationStateData;
|
private readonly AnimationStateData animationStateData;
|
||||||
|
|
||||||
private Skeleton skeleton;
|
private readonly Skeleton skeleton;
|
||||||
private AnimationState animationState;
|
private readonly AnimationState animationState;
|
||||||
|
|
||||||
private SkeletonClipping clipping = new();
|
private readonly SkeletonClipping clipping = new();
|
||||||
|
|
||||||
public SpineObject41(string skelPath, string atlasPath) : base(skelPath, atlasPath)
|
public SpineObject41(string skelPath, string atlasPath) : base(skelPath, atlasPath)
|
||||||
{
|
{
|
||||||
@@ -170,6 +181,48 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
return new RectangleF(x, y, w, h);
|
return new RectangleF(x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override RectangleF getBounds()
|
||||||
|
{
|
||||||
|
// 初始化临时对象
|
||||||
|
var maxDuration = 0f;
|
||||||
|
var tmpSkeleton = new Skeleton(skeletonData) { Skin = new(Guid.NewGuid().ToString()) };
|
||||||
|
var tmpAnimationState = new AnimationState(animationStateData);
|
||||||
|
tmpSkeleton.ScaleX = skeleton.ScaleX;
|
||||||
|
tmpSkeleton.ScaleY = skeleton.ScaleY;
|
||||||
|
tmpSkeleton.X = skeleton.X;
|
||||||
|
tmpSkeleton.Y = skeleton.Y;
|
||||||
|
foreach (var sk in loadedSkins) tmpSkeleton.Skin.AddSkin(skeletonData.FindSkin(sk));
|
||||||
|
foreach (var tr in animationState.Tracks.Select((_, i) => i).Where(i => animationState.Tracks.Items[i] is not null))
|
||||||
|
{
|
||||||
|
var ani = animationState.GetCurrent(tr).Animation;
|
||||||
|
tmpAnimationState.SetAnimation(tr, ani, true);
|
||||||
|
if (ani.Duration > maxDuration) maxDuration = ani.Duration;
|
||||||
|
}
|
||||||
|
tmpSkeleton.SetSlotsToSetupPose();
|
||||||
|
tmpAnimationState.Update(0);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
//tmpSkeleton.Update(0);
|
||||||
|
tmpSkeleton.UpdateWorldTransform();
|
||||||
|
|
||||||
|
// 切成 100 帧获取边界最大值
|
||||||
|
var bounds = getCurrentBounds();
|
||||||
|
float[] _ = [];
|
||||||
|
for (float tick = 0, delta = maxDuration / 100; tick < maxDuration; tick += delta)
|
||||||
|
{
|
||||||
|
tmpSkeleton.GetBounds(out var x, out var y, out var w, out var h, ref _);
|
||||||
|
if (x < bounds.X) bounds.X = x;
|
||||||
|
if (y < bounds.Y) bounds.Y = y;
|
||||||
|
if (w > bounds.Width) bounds.Width = w;
|
||||||
|
if (h > bounds.Height) bounds.Height = h;
|
||||||
|
tmpAnimationState.Update(delta);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
//tmpSkeleton.Update(delta);
|
||||||
|
tmpSkeleton.UpdateWorldTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void update(float delta)
|
protected override void update(float delta)
|
||||||
{
|
{
|
||||||
animationState.Update(delta);
|
animationState.Update(delta);
|
||||||
@@ -178,18 +231,6 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
skeleton.UpdateWorldTransform();
|
skeleton.UpdateWorldTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SFML.Graphics.BlendMode GetSFMLBlendMode(BlendMode spineBlendMode)
|
|
||||||
{
|
|
||||||
return spineBlendMode switch
|
|
||||||
{
|
|
||||||
BlendMode.Normal => SFMLBlendMode.NormalPma,
|
|
||||||
BlendMode.Additive => SFMLBlendMode.AdditivePma,
|
|
||||||
BlendMode.Multiply => SFMLBlendMode.MultiplyPma,
|
|
||||||
BlendMode.Screen => SFMLBlendMode.ScreenPma,
|
|
||||||
_ => throw new NotImplementedException($"{spineBlendMode}"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
|
protected override void draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
|
||||||
{
|
{
|
||||||
triangleVertices.Clear();
|
triangleVertices.Clear();
|
||||||
|
|||||||
@@ -13,7 +13,17 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
[SpineImplementation(SpineVersion.V42)]
|
[SpineImplementation(SpineVersion.V42)]
|
||||||
internal class Spineobject42 : Spine.SpineObject
|
internal class Spineobject42 : Spine.SpineObject
|
||||||
{
|
{
|
||||||
private static readonly Animation EmptyAnimation = new(EMPTY_ANIMATION, [], 0);
|
private SFML.Graphics.BlendMode GetSFMLBlendMode(BlendMode spineBlendMode)
|
||||||
|
{
|
||||||
|
return spineBlendMode switch
|
||||||
|
{
|
||||||
|
BlendMode.Normal => SFMLBlendMode.NormalPma,
|
||||||
|
BlendMode.Additive => SFMLBlendMode.AdditivePma,
|
||||||
|
BlendMode.Multiply => SFMLBlendMode.MultiplyPma,
|
||||||
|
BlendMode.Screen => SFMLBlendMode.ScreenPma,
|
||||||
|
_ => throw new NotImplementedException($"{spineBlendMode}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private class TextureLoader : SpineRuntime42.TextureLoader
|
private class TextureLoader : SpineRuntime42.TextureLoader
|
||||||
{
|
{
|
||||||
@@ -34,18 +44,19 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TextureLoader textureLoader = new();
|
private static readonly TextureLoader textureLoader = new();
|
||||||
|
private static readonly Animation EmptyAnimation = new(EMPTY_ANIMATION, [], 0);
|
||||||
|
|
||||||
private Atlas atlas;
|
private readonly Atlas atlas;
|
||||||
private SkeletonBinary? skeletonBinary;
|
private readonly SkeletonBinary? skeletonBinary;
|
||||||
private SkeletonJson? skeletonJson;
|
private readonly SkeletonJson? skeletonJson;
|
||||||
private SkeletonData skeletonData;
|
private readonly SkeletonData skeletonData;
|
||||||
private AnimationStateData animationStateData;
|
private readonly AnimationStateData animationStateData;
|
||||||
|
|
||||||
private Skeleton skeleton;
|
private readonly Skeleton skeleton;
|
||||||
private AnimationState animationState;
|
private readonly AnimationState animationState;
|
||||||
|
|
||||||
private SkeletonClipping clipping = new();
|
private readonly SkeletonClipping clipping = new();
|
||||||
|
|
||||||
public Spineobject42(string skelPath, string atlasPath) : base(skelPath, atlasPath)
|
public Spineobject42(string skelPath, string atlasPath) : base(skelPath, atlasPath)
|
||||||
{
|
{
|
||||||
@@ -170,6 +181,48 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
return new RectangleF(x, y, w, h);
|
return new RectangleF(x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override RectangleF getBounds()
|
||||||
|
{
|
||||||
|
// 初始化临时对象
|
||||||
|
var maxDuration = 0f;
|
||||||
|
var tmpSkeleton = new Skeleton(skeletonData) { Skin = new(Guid.NewGuid().ToString()) };
|
||||||
|
var tmpAnimationState = new AnimationState(animationStateData);
|
||||||
|
tmpSkeleton.ScaleX = skeleton.ScaleX;
|
||||||
|
tmpSkeleton.ScaleY = skeleton.ScaleY;
|
||||||
|
tmpSkeleton.X = skeleton.X;
|
||||||
|
tmpSkeleton.Y = skeleton.Y;
|
||||||
|
foreach (var sk in loadedSkins) tmpSkeleton.Skin.AddSkin(skeletonData.FindSkin(sk));
|
||||||
|
foreach (var tr in animationState.Tracks.Select((_, i) => i).Where(i => animationState.Tracks.Items[i] is not null))
|
||||||
|
{
|
||||||
|
var ani = animationState.GetCurrent(tr).Animation;
|
||||||
|
tmpAnimationState.SetAnimation(tr, ani, true);
|
||||||
|
if (ani.Duration > maxDuration) maxDuration = ani.Duration;
|
||||||
|
}
|
||||||
|
tmpSkeleton.SetSlotsToSetupPose();
|
||||||
|
tmpAnimationState.Update(0);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
tmpSkeleton.Update(0);
|
||||||
|
tmpSkeleton.UpdateWorldTransform(Skeleton.Physics.Update);
|
||||||
|
|
||||||
|
// 切成 100 帧获取边界最大值
|
||||||
|
var bounds = getCurrentBounds();
|
||||||
|
float[] _ = [];
|
||||||
|
for (float tick = 0, delta = maxDuration / 100; tick < maxDuration; tick += delta)
|
||||||
|
{
|
||||||
|
tmpSkeleton.GetBounds(out var x, out var y, out var w, out var h, ref _);
|
||||||
|
if (x < bounds.X) bounds.X = x;
|
||||||
|
if (y < bounds.Y) bounds.Y = y;
|
||||||
|
if (w > bounds.Width) bounds.Width = w;
|
||||||
|
if (h > bounds.Height) bounds.Height = h;
|
||||||
|
tmpAnimationState.Update(delta);
|
||||||
|
tmpAnimationState.Apply(tmpSkeleton);
|
||||||
|
tmpSkeleton.Update(delta);
|
||||||
|
tmpSkeleton.UpdateWorldTransform(Skeleton.Physics.Update);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void update(float delta)
|
protected override void update(float delta)
|
||||||
{
|
{
|
||||||
animationState.Update(delta);
|
animationState.Update(delta);
|
||||||
@@ -178,18 +231,6 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
|||||||
skeleton.UpdateWorldTransform(Skeleton.Physics.Update);
|
skeleton.UpdateWorldTransform(Skeleton.Physics.Update);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SFML.Graphics.BlendMode GetSFMLBlendMode(BlendMode spineBlendMode)
|
|
||||||
{
|
|
||||||
return spineBlendMode switch
|
|
||||||
{
|
|
||||||
BlendMode.Normal => SFMLBlendMode.NormalPma,
|
|
||||||
BlendMode.Additive => SFMLBlendMode.AdditivePma,
|
|
||||||
BlendMode.Multiply => SFMLBlendMode.MultiplyPma,
|
|
||||||
BlendMode.Screen => SFMLBlendMode.ScreenPma,
|
|
||||||
_ => throw new NotImplementedException($"{spineBlendMode}"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
|
protected override void draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
|
||||||
{
|
{
|
||||||
triangleVertices.Clear();
|
triangleVertices.Clear();
|
||||||
|
|||||||
@@ -443,8 +443,8 @@ namespace SpineViewer.Spine
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取当前参数下包围盒最大范围, 不是精确值
|
/// 获取当前参数下包围盒最大范围, 不是精确值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
//public RectangleF GetBounds() { }
|
public RectangleF GetBounds() { lock (_lock) return getBounds(); }
|
||||||
//protected abstract RectangleF getBounds();
|
protected abstract RectangleF getBounds();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 更新内部状态
|
/// 更新内部状态
|
||||||
|
|||||||
Reference in New Issue
Block a user