diff --git a/SpineViewer/Spine/Implementations/Spine/Spine21.cs b/SpineViewer/Spine/Implementations/Spine/Spine21.cs index 818de4a..16b042a 100644 --- a/SpineViewer/Spine/Implementations/Spine/Spine21.cs +++ b/SpineViewer/Spine/Implementations/Spine/Spine21.cs @@ -47,7 +47,7 @@ namespace SpineViewer.Spine.Implementations.Spine // 2.1.x 不支持剪裁 //private SkeletonClipping clipping = new(); - public Spine21(string skelPath, string? atlasPath = null) : base(skelPath, atlasPath) + public Spine21(string skelPath, string atlasPath) : base(skelPath, atlasPath) { atlas = new Atlas(AtlasPath, textureLoader); try @@ -76,12 +76,12 @@ namespace SpineViewer.Spine.Implementations.Spine foreach (var skin in skeletonData.Skins) skinNames.Add(skin.Name); - animationStateData = new AnimationStateData(skeletonData); - skeleton = new Skeleton(skeletonData); - animationState = new AnimationState(animationStateData); - foreach (var anime in skeletonData.Animations) animationNames.Add(anime.Name); + + skeleton = new Skeleton(skeletonData); + animationStateData = new AnimationStateData(skeletonData); + animationState = new AnimationState(animationStateData); } protected override void Dispose(bool disposing) diff --git a/SpineViewer/Spine/Implementations/Spine/Spine36.cs b/SpineViewer/Spine/Implementations/Spine/Spine36.cs index c9ab7b8..05124aa 100644 --- a/SpineViewer/Spine/Implementations/Spine/Spine36.cs +++ b/SpineViewer/Spine/Implementations/Spine/Spine36.cs @@ -46,7 +46,7 @@ namespace SpineViewer.Spine.Implementations.Spine private SkeletonClipping clipping = new(); - public Spine36(string skelPath, string? atlasPath = null) : base(skelPath, atlasPath) + public Spine36(string skelPath, string atlasPath) : base(skelPath, atlasPath) { atlas = new Atlas(AtlasPath, textureLoader); try @@ -75,12 +75,12 @@ namespace SpineViewer.Spine.Implementations.Spine foreach (var skin in skeletonData.Skins) skinNames.Add(skin.Name); - animationStateData = new AnimationStateData(skeletonData); - skeleton = new Skeleton(skeletonData); - animationState = new AnimationState(animationStateData); - foreach (var anime in skeletonData.Animations) animationNames.Add(anime.Name); + + skeleton = new Skeleton(skeletonData); + animationStateData = new AnimationStateData(skeletonData); + animationState = new AnimationState(animationStateData); } protected override void Dispose(bool disposing) diff --git a/SpineViewer/Spine/Implementations/Spine/Spine37.cs b/SpineViewer/Spine/Implementations/Spine/Spine37.cs index 8ac850b..2c3837b 100644 --- a/SpineViewer/Spine/Implementations/Spine/Spine37.cs +++ b/SpineViewer/Spine/Implementations/Spine/Spine37.cs @@ -44,7 +44,7 @@ namespace SpineViewer.Spine.Implementations.Spine private SkeletonClipping clipping = new(); - public Spine37(string skelPath, string? atlasPath = null) : base(skelPath, atlasPath) + public Spine37(string skelPath, string atlasPath) : base(skelPath, atlasPath) { atlas = new Atlas(AtlasPath, textureLoader); try @@ -73,12 +73,12 @@ namespace SpineViewer.Spine.Implementations.Spine foreach (var skin in skeletonData.Skins) skinNames.Add(skin.Name); - animationStateData = new AnimationStateData(skeletonData); - skeleton = new Skeleton(skeletonData); - animationState = new AnimationState(animationStateData); - foreach (var anime in skeletonData.Animations) animationNames.Add(anime.Name); + + skeleton = new Skeleton(skeletonData); + animationStateData = new AnimationStateData(skeletonData); + animationState = new AnimationState(animationStateData); } protected override void Dispose(bool disposing) diff --git a/SpineViewer/Spine/Implementations/Spine/Spine38.cs b/SpineViewer/Spine/Implementations/Spine/Spine38.cs index 1af6b81..5209e3b 100644 --- a/SpineViewer/Spine/Implementations/Spine/Spine38.cs +++ b/SpineViewer/Spine/Implementations/Spine/Spine38.cs @@ -50,7 +50,7 @@ namespace SpineViewer.Spine.Implementations.Spine private SkeletonClipping clipping = new(); - public Spine38(string skelPath, string? atlasPath = null) : base(skelPath, atlasPath) + public Spine38(string skelPath, string atlasPath) : base(skelPath, atlasPath) { atlas = new Atlas(AtlasPath, textureLoader); try @@ -79,12 +79,12 @@ namespace SpineViewer.Spine.Implementations.Spine foreach (var skin in skeletonData.Skins) skinNames.Add(skin.Name); - animationStateData = new AnimationStateData(skeletonData); - skeleton = new Skeleton(skeletonData); - animationState = new AnimationState(animationStateData); - foreach (var anime in skeletonData.Animations) animationNames.Add(anime.Name); + + skeleton = new Skeleton(skeletonData); + animationStateData = new AnimationStateData(skeletonData); + animationState = new AnimationState(animationStateData); } protected override void Dispose(bool disposing) diff --git a/SpineViewer/Spine/Implementations/Spine/Spine40.cs b/SpineViewer/Spine/Implementations/Spine/Spine40.cs index 1542e0f..a43561b 100644 --- a/SpineViewer/Spine/Implementations/Spine/Spine40.cs +++ b/SpineViewer/Spine/Implementations/Spine/Spine40.cs @@ -46,7 +46,7 @@ namespace SpineViewer.Spine.Implementations.Spine private SkeletonClipping clipping = new(); - public Spine40(string skelPath, string? atlasPath = null) : base(skelPath, atlasPath) + public Spine40(string skelPath, string atlasPath) : base(skelPath, atlasPath) { atlas = new Atlas(AtlasPath, textureLoader); try @@ -75,12 +75,12 @@ namespace SpineViewer.Spine.Implementations.Spine foreach (var skin in skeletonData.Skins) skinNames.Add(skin.Name); - animationStateData = new AnimationStateData(skeletonData); - skeleton = new Skeleton(skeletonData); - animationState = new AnimationState(animationStateData); - foreach (var anime in skeletonData.Animations) animationNames.Add(anime.Name); + + skeleton = new Skeleton(skeletonData); + animationStateData = new AnimationStateData(skeletonData); + animationState = new AnimationState(animationStateData); } protected override void Dispose(bool disposing) diff --git a/SpineViewer/Spine/Implementations/Spine/Spine41.cs b/SpineViewer/Spine/Implementations/Spine/Spine41.cs index 129fde7..701413f 100644 --- a/SpineViewer/Spine/Implementations/Spine/Spine41.cs +++ b/SpineViewer/Spine/Implementations/Spine/Spine41.cs @@ -46,7 +46,7 @@ namespace SpineViewer.Spine.Implementations.Spine private SkeletonClipping clipping = new(); - public Spine41(string skelPath, string? atlasPath = null) : base(skelPath, atlasPath) + public Spine41(string skelPath, string atlasPath) : base(skelPath, atlasPath) { atlas = new Atlas(AtlasPath, textureLoader); try @@ -75,12 +75,12 @@ namespace SpineViewer.Spine.Implementations.Spine foreach (var skin in skeletonData.Skins) skinNames.Add(skin.Name); - animationStateData = new AnimationStateData(skeletonData); - skeleton = new Skeleton(skeletonData); - animationState = new AnimationState(animationStateData); - foreach (var anime in skeletonData.Animations) animationNames.Add(anime.Name); + + skeleton = new Skeleton(skeletonData); + animationStateData = new AnimationStateData(skeletonData); + animationState = new AnimationState(animationStateData); } protected override void Dispose(bool disposing) diff --git a/SpineViewer/Spine/Implementations/Spine/Spine42.cs b/SpineViewer/Spine/Implementations/Spine/Spine42.cs index b1a46e7..0717ec0 100644 --- a/SpineViewer/Spine/Implementations/Spine/Spine42.cs +++ b/SpineViewer/Spine/Implementations/Spine/Spine42.cs @@ -46,7 +46,7 @@ namespace SpineViewer.Spine.Implementations.Spine private SkeletonClipping clipping = new(); - public Spine42(string skelPath, string? atlasPath = null) : base(skelPath, atlasPath) + public Spine42(string skelPath, string atlasPath) : base(skelPath, atlasPath) { atlas = new Atlas(AtlasPath, textureLoader); try @@ -75,12 +75,12 @@ namespace SpineViewer.Spine.Implementations.Spine foreach (var skin in skeletonData.Skins) skinNames.Add(skin.Name); - animationStateData = new AnimationStateData(skeletonData); - skeleton = new Skeleton(skeletonData); - animationState = new AnimationState(animationStateData); - foreach (var anime in skeletonData.Animations) animationNames.Add(anime.Name); + + skeleton = new Skeleton(skeletonData); + animationStateData = new AnimationStateData(skeletonData); + animationState = new AnimationState(animationStateData); } protected override void Dispose(bool disposing) diff --git a/SpineViewer/Spine/Spine.cs b/SpineViewer/Spine/Spine.cs index 44ec418..ce3f7ee 100644 --- a/SpineViewer/Spine/Spine.cs +++ b/SpineViewer/Spine/Spine.cs @@ -26,23 +26,22 @@ namespace SpineViewer.Spine /// /// 空动画标记 /// - public const string EMPTY_ANIMATION = ""; + protected const string EMPTY_ANIMATION = ""; /// /// 预览图宽 /// - public const uint PREVIEW_WIDTH = 256; + protected const uint PREVIEW_WIDTH = 256; /// /// 预览图高 /// - public const uint PREVIEW_HEIGHT = 256; + protected const uint PREVIEW_HEIGHT = 256; /// /// 缩放最小值 /// - public const float SCALE_MIN = 0.001f; - + protected const float SCALE_MIN = 0.001f; /// /// 创建特定版本的 Spine @@ -50,10 +49,31 @@ namespace SpineViewer.Spine public static Spine New(SpineVersion version, string skelPath, string? atlasPath = null) { if (version == SpineVersion.Auto) version = SpineHelper.GetVersion(skelPath); - var spine = New(version, [skelPath, atlasPath]); + atlasPath ??= Path.ChangeExtension(skelPath, ".atlas"); + return New(version, [skelPath, atlasPath]).PostInit(); + } - // 统一初始化 - spine.initBounds = spine.Bounds; + /// + /// 构造函数 + /// + public Spine(string skelPath, string atlasPath) + { + Version = GetType().GetCustomAttribute().ImplementationKey; + AssetsDir = Directory.GetParent(skelPath).FullName; + SkelPath = Path.GetFullPath(skelPath); + AtlasPath = Path.GetFullPath(atlasPath); + Name = Path.GetFileNameWithoutExtension(skelPath); + } + + /// + /// 构造函数之后的初始化工作 + /// + private Spine PostInit() + { + SkinNames = skinNames.AsReadOnly(); + AnimationNames = animationNames.AsReadOnly(); + + InitBounds = Bounds; // XXX: tex 没办法在这里主动 Dispose // 批量添加在获取预览图的时候极大概率会和预览线程死锁 @@ -61,9 +81,9 @@ namespace SpineViewer.Spine // 除此之外, 似乎还和 tex 的 Dispose 有关 // 如果不对 tex 进行 Dispose, 那么不管是否 Draw 都正常不会死锁 var tex = new SFML.Graphics.RenderTexture(PREVIEW_WIDTH, PREVIEW_HEIGHT); - tex.SetView(spine.InitBounds.GetView(PREVIEW_WIDTH, PREVIEW_HEIGHT)); + tex.SetView(InitBounds.GetView(PREVIEW_WIDTH, PREVIEW_HEIGHT)); tex.Clear(SFML.Graphics.Color.Transparent); - tex.Draw(spine); + tex.Draw(this); tex.Display(); using (var img = tex.Texture.CopyToImage()) @@ -73,50 +93,27 @@ namespace SpineViewer.Spine // 必须重复构造一个副本才能摆脱对流的依赖, 否则之后使用会报错 using var stream = new MemoryStream(imgBuffer); using var bitmap = new Bitmap(stream); - spine.preview = new Bitmap(bitmap); + Preview = new Bitmap(bitmap); } } // 取最后一个作为初始, 尽可能去显示非默认的内容 - spine.Skin = spine.SkinNames.Last(); - spine.Track0Animation = spine.AnimationNames.Last(); + Skin = SkinNames.Last(); + Track0Animation = AnimationNames.Last(); - return spine; - } - - /// - /// 构造函数 - /// - public Spine(string skelPath, string? atlasPath = null) - { - // 获取子类类型 - var type = GetType(); - var attr = type.GetCustomAttribute(); - if (attr is null) - { - throw new InvalidOperationException($"Class {type.Name} has no SpineImplementationAttribute"); - } - - atlasPath ??= Path.ChangeExtension(skelPath, ".atlas"); - - // 设置 Version - Version = attr.ImplementationKey; - AssetsDir = Directory.GetParent(skelPath).FullName; - SkelPath = Path.GetFullPath(skelPath); - AtlasPath = Path.GetFullPath(atlasPath); - Name = Path.GetFileNameWithoutExtension(skelPath); + return this; } ~Spine() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) { preview?.Dispose(); } + protected virtual void Dispose(bool disposing) { Preview?.Dispose(); } #region 属性 | [0] 基本信息 /// /// 获取所属版本 /// - [TypeConverter(typeof(VersionConverter))] + [TypeConverter(typeof(SpineVersionConverter))] [Category("[0] 基本信息"), DisplayName("运行时版本")] public SpineVersion Version { get; } @@ -202,8 +199,7 @@ namespace SpineViewer.Spine /// /// 包含的所有皮肤名称 /// - [Browsable(false)] - public ReadOnlyCollection SkinNames { get => skinNames.AsReadOnly(); } + public ReadOnlyCollection SkinNames { get; private set; } protected List skinNames = []; /// @@ -216,8 +212,7 @@ namespace SpineViewer.Spine /// /// 包含的所有动画名称 /// - [Browsable(false)] - public ReadOnlyCollection AnimationNames { get => animationNames.AsReadOnly(); } + public ReadOnlyCollection AnimationNames { get; private set; } protected List animationNames = [EMPTY_ANIMATION]; /// @@ -243,16 +238,6 @@ namespace SpineViewer.Spine [Browsable(false)] public bool IsDebug { get; set; } = false; - /// - /// 包围盒颜色 - /// - protected static readonly SFML.Graphics.Color BoundsColor = new(120, 200, 0); - - /// - /// 包围盒顶点数组 - /// - protected readonly SFML.Graphics.VertexArray boundsVertices = new(SFML.Graphics.PrimitiveType.LineStrip, 5); - /// /// 显示纹理 /// @@ -268,7 +253,7 @@ namespace SpineViewer.Spine /// /// 显示骨骼 /// - [Category("[4] 调试"), DisplayName("显示骨骼")] + [Category("[4] 调试"), DisplayName("显示骨架")] public bool DebugBones { get; set; } = false; #endregion @@ -294,15 +279,13 @@ namespace SpineViewer.Spine /// 初始状态下的骨骼包围盒 /// [Browsable(false)] - public RectangleF InitBounds { get => initBounds; } - private RectangleF initBounds; + public RectangleF InitBounds { get; private set; } /// /// 骨骼预览图 /// [Browsable(false)] - public Image Preview { get => preview; } - private Image preview; + public Image Preview { get; private set; } /// /// 获取动画时长, 如果动画不存在则返回 0 @@ -326,6 +309,16 @@ namespace SpineViewer.Spine /// protected readonly SFML.Graphics.VertexArray vertexArray = new(SFML.Graphics.PrimitiveType.Triangles); + /// + /// 包围盒颜色 + /// + protected static readonly SFML.Graphics.Color BoundsColor = new(120, 200, 0); + + /// + /// 包围盒顶点数组 + /// + protected readonly SFML.Graphics.VertexArray boundsVertices = new(SFML.Graphics.PrimitiveType.LineStrip, 5); + /// /// SFML.Graphics.Drawable 接口实现 /// diff --git a/SpineViewer/Spine/TypeConverter.cs b/SpineViewer/Spine/TypeConverter.cs index fad151e..e0968fc 100644 --- a/SpineViewer/Spine/TypeConverter.cs +++ b/SpineViewer/Spine/TypeConverter.cs @@ -9,9 +9,9 @@ using System.Threading.Tasks; namespace SpineViewer.Spine { - public class VersionConverter : EnumConverter + public class SpineVersionConverter : EnumConverter { - public VersionConverter() : base(typeof(SpineVersion)) { } + public SpineVersionConverter() : base(typeof(SpineVersion)) { } public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type? destinationType) {