增加GetBounds获取最大包围盒方法
This commit is contained in:
@@ -206,49 +206,53 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
|
||||
protected override RectangleF getCurrentBounds()
|
||||
{
|
||||
float[] temp = new float[8];
|
||||
var drawOrderItems = skeleton.DrawOrder;
|
||||
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);
|
||||
}
|
||||
}
|
||||
skeleton.GetBounds(out var x, out var y, out var w, out var h);
|
||||
return new RectangleF(x, y, w, h);
|
||||
}
|
||||
|
||||
if (vertices != null)
|
||||
{
|
||||
for (int ii = 0; ii < verticesLength; ii += 2)
|
||||
{
|
||||
float vx = vertices[ii], vy = vertices[ii + 1];
|
||||
minX = Math.Min(minX, vx);
|
||||
minY = Math.Min(minY, vy);
|
||||
maxX = Math.Max(maxX, vx);
|
||||
maxY = Math.Max(maxY, vy);
|
||||
}
|
||||
}
|
||||
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.Key, k.Value, v);
|
||||
}
|
||||
return new RectangleF(minX, minY, maxX - minX, maxY - minY);
|
||||
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 bounds;
|
||||
}
|
||||
|
||||
protected override void update(float delta)
|
||||
|
||||
@@ -210,6 +210,52 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
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)
|
||||
{
|
||||
animationState.Update(delta);
|
||||
@@ -218,18 +264,6 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
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)
|
||||
{
|
||||
triangleVertices.Clear();
|
||||
|
||||
@@ -181,6 +181,52 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
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)
|
||||
{
|
||||
animationState.Update(delta);
|
||||
@@ -189,18 +235,6 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
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)
|
||||
{
|
||||
triangleVertices.Clear();
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using SpineRuntime38;
|
||||
using SpineRuntime38.Attachments;
|
||||
using SpineViewer.Utils;
|
||||
@@ -14,7 +15,17 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
[SpineImplementation(SpineVersion.V38)]
|
||||
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
|
||||
{
|
||||
@@ -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 SkeletonBinary? skeletonBinary;
|
||||
private SkeletonJson? skeletonJson;
|
||||
private SkeletonData skeletonData;
|
||||
private AnimationStateData animationStateData;
|
||||
private readonly Atlas atlas;
|
||||
private readonly SkeletonBinary? skeletonBinary;
|
||||
private readonly SkeletonJson? skeletonJson;
|
||||
private readonly SkeletonData skeletonData;
|
||||
private readonly AnimationStateData animationStateData;
|
||||
|
||||
private Skeleton skeleton;
|
||||
private AnimationState animationState;
|
||||
private readonly Skeleton skeleton;
|
||||
private readonly AnimationState animationState;
|
||||
|
||||
private SkeletonClipping clipping = new();
|
||||
private readonly SkeletonClipping clipping = new();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
animationState.Update(delta);
|
||||
@@ -182,18 +236,6 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
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)
|
||||
{
|
||||
triangleVertices.Clear();
|
||||
|
||||
@@ -13,7 +13,17 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
[SpineImplementation(SpineVersion.V40)]
|
||||
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
|
||||
{
|
||||
@@ -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 SkeletonBinary? skeletonBinary;
|
||||
private SkeletonJson? skeletonJson;
|
||||
private SkeletonData skeletonData;
|
||||
private AnimationStateData animationStateData;
|
||||
private readonly Atlas atlas;
|
||||
private readonly SkeletonBinary? skeletonBinary;
|
||||
private readonly SkeletonJson? skeletonJson;
|
||||
private readonly SkeletonData skeletonData;
|
||||
private readonly AnimationStateData animationStateData;
|
||||
|
||||
private Skeleton skeleton;
|
||||
private AnimationState animationState;
|
||||
private readonly Skeleton skeleton;
|
||||
private readonly AnimationState animationState;
|
||||
|
||||
private SkeletonClipping clipping = new();
|
||||
private readonly SkeletonClipping clipping = new();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
animationState.Update(delta);
|
||||
@@ -178,18 +231,6 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
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)
|
||||
{
|
||||
triangleVertices.Clear();
|
||||
|
||||
@@ -13,7 +13,17 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
[SpineImplementation(SpineVersion.V41)]
|
||||
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
|
||||
{
|
||||
@@ -35,17 +45,18 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
}
|
||||
|
||||
private static TextureLoader textureLoader = new();
|
||||
private static readonly Animation EmptyAnimation = new(EMPTY_ANIMATION, [], 0);
|
||||
|
||||
private Atlas atlas;
|
||||
private SkeletonBinary? skeletonBinary;
|
||||
private SkeletonJson? skeletonJson;
|
||||
private SkeletonData skeletonData;
|
||||
private AnimationStateData animationStateData;
|
||||
private readonly Atlas atlas;
|
||||
private readonly SkeletonBinary? skeletonBinary;
|
||||
private readonly SkeletonJson? skeletonJson;
|
||||
private readonly SkeletonData skeletonData;
|
||||
private readonly AnimationStateData animationStateData;
|
||||
|
||||
private Skeleton skeleton;
|
||||
private AnimationState animationState;
|
||||
private readonly Skeleton skeleton;
|
||||
private readonly AnimationState animationState;
|
||||
|
||||
private SkeletonClipping clipping = new();
|
||||
private readonly SkeletonClipping clipping = new();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
animationState.Update(delta);
|
||||
@@ -178,18 +231,6 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
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)
|
||||
{
|
||||
triangleVertices.Clear();
|
||||
|
||||
@@ -13,7 +13,17 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
[SpineImplementation(SpineVersion.V42)]
|
||||
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
|
||||
{
|
||||
@@ -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 SkeletonBinary? skeletonBinary;
|
||||
private SkeletonJson? skeletonJson;
|
||||
private SkeletonData skeletonData;
|
||||
private AnimationStateData animationStateData;
|
||||
private readonly Atlas atlas;
|
||||
private readonly SkeletonBinary? skeletonBinary;
|
||||
private readonly SkeletonJson? skeletonJson;
|
||||
private readonly SkeletonData skeletonData;
|
||||
private readonly AnimationStateData animationStateData;
|
||||
|
||||
private Skeleton skeleton;
|
||||
private AnimationState animationState;
|
||||
private readonly Skeleton skeleton;
|
||||
private readonly AnimationState animationState;
|
||||
|
||||
private SkeletonClipping clipping = new();
|
||||
private readonly SkeletonClipping clipping = new();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
animationState.Update(delta);
|
||||
@@ -178,18 +231,6 @@ namespace SpineViewer.Spine.Implementations.SpineObject
|
||||
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)
|
||||
{
|
||||
triangleVertices.Clear();
|
||||
|
||||
@@ -443,8 +443,8 @@ namespace SpineViewer.Spine
|
||||
/// <summary>
|
||||
/// 获取当前参数下包围盒最大范围, 不是精确值
|
||||
/// </summary>
|
||||
//public RectangleF GetBounds() { }
|
||||
//protected abstract RectangleF getBounds();
|
||||
public RectangleF GetBounds() { lock (_lock) return getBounds(); }
|
||||
protected abstract RectangleF getBounds();
|
||||
|
||||
/// <summary>
|
||||
/// 更新内部状态
|
||||
|
||||
Reference in New Issue
Block a user