diff --git a/Spine/Implementations/SpineWrappers/V21/SpineObjectData21.cs b/Spine/Implementations/SpineWrappers/V21/SpineObjectData21.cs index 6959e60..4a7c9a1 100644 --- a/Spine/Implementations/SpineWrappers/V21/SpineObjectData21.cs +++ b/Spine/Implementations/SpineWrappers/V21/SpineObjectData21.cs @@ -26,10 +26,11 @@ namespace Spine.Implementations.SpineWrappers.V21 private readonly ImmutableArray _animations; private readonly FrozenDictionary _animationsByName; - public SpineObjectData21(string skelPath, string atlasPath) : base(skelPath, atlasPath) + public SpineObjectData21(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader) + : base(skelPath, atlasPath, textureLoader) { // 加载 atlas - try { _atlas = new Atlas(atlasPath, _textureLoader); } + try { _atlas = new Atlas(atlasPath, textureLoader); } catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); } try diff --git a/Spine/Implementations/SpineWrappers/V36/SpineObjectData36.cs b/Spine/Implementations/SpineWrappers/V36/SpineObjectData36.cs index f38bcd0..a389679 100644 --- a/Spine/Implementations/SpineWrappers/V36/SpineObjectData36.cs +++ b/Spine/Implementations/SpineWrappers/V36/SpineObjectData36.cs @@ -26,10 +26,11 @@ namespace Spine.Implementations.SpineWrappers.V36 private readonly ImmutableArray _animations; private readonly FrozenDictionary _animationsByName; - public SpineObjectData36(string skelPath, string atlasPath) : base(skelPath, atlasPath) + public SpineObjectData36(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader) + : base(skelPath, atlasPath, textureLoader) { // 加载 atlas - try { _atlas = new Atlas(atlasPath, _textureLoader); } + try { _atlas = new Atlas(atlasPath, textureLoader); } catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); } try diff --git a/Spine/Implementations/SpineWrappers/V37/SpineObjectData37.cs b/Spine/Implementations/SpineWrappers/V37/SpineObjectData37.cs index 8774bff..470eec7 100644 --- a/Spine/Implementations/SpineWrappers/V37/SpineObjectData37.cs +++ b/Spine/Implementations/SpineWrappers/V37/SpineObjectData37.cs @@ -26,10 +26,11 @@ namespace Spine.Implementations.SpineWrappers.V37 private readonly ImmutableArray _animations; private readonly FrozenDictionary _animationsByName; - public SpineObjectData37(string skelPath, string atlasPath) : base(skelPath, atlasPath) + public SpineObjectData37(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader) + : base(skelPath, atlasPath, textureLoader) { // 加载 atlas - try { _atlas = new Atlas(atlasPath, _textureLoader); } + try { _atlas = new Atlas(atlasPath, textureLoader); } catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); } try diff --git a/Spine/Implementations/SpineWrappers/V38/SpineObjectData38.cs b/Spine/Implementations/SpineWrappers/V38/SpineObjectData38.cs index 1138177..0204041 100644 --- a/Spine/Implementations/SpineWrappers/V38/SpineObjectData38.cs +++ b/Spine/Implementations/SpineWrappers/V38/SpineObjectData38.cs @@ -27,10 +27,11 @@ namespace Spine.Implementations.SpineWrappers.V38 private readonly ImmutableArray _animations; private readonly FrozenDictionary _animationsByName; - public SpineObjectData38(string skelPath, string atlasPath) : base(skelPath, atlasPath) + public SpineObjectData38(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader) + : base(skelPath, atlasPath, textureLoader) { // 加载 atlas - try { _atlas = new Atlas(atlasPath, _textureLoader); } + try { _atlas = new Atlas(atlasPath, textureLoader); } catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); } try diff --git a/Spine/Implementations/SpineWrappers/V40/SpineObjectData40.cs b/Spine/Implementations/SpineWrappers/V40/SpineObjectData40.cs index b3852f4..bc035d7 100644 --- a/Spine/Implementations/SpineWrappers/V40/SpineObjectData40.cs +++ b/Spine/Implementations/SpineWrappers/V40/SpineObjectData40.cs @@ -26,10 +26,11 @@ namespace Spine.Implementations.SpineWrappers.V40 private readonly ImmutableArray _animations; private readonly FrozenDictionary _animationsByName; - public SpineObjectData40(string skelPath, string atlasPath) : base(skelPath, atlasPath) + public SpineObjectData40(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader) + : base(skelPath, atlasPath, textureLoader) { // 加载 atlas - try { _atlas = new Atlas(atlasPath, _textureLoader); } + try { _atlas = new Atlas(atlasPath, textureLoader); } catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); } // 加载 skel diff --git a/Spine/Implementations/SpineWrappers/V41/SpineObjectData41.cs b/Spine/Implementations/SpineWrappers/V41/SpineObjectData41.cs index b5755b0..18ed63b 100644 --- a/Spine/Implementations/SpineWrappers/V41/SpineObjectData41.cs +++ b/Spine/Implementations/SpineWrappers/V41/SpineObjectData41.cs @@ -26,10 +26,11 @@ namespace Spine.Implementations.SpineWrappers.V41 private readonly ImmutableArray _animations; private readonly FrozenDictionary _animationsByName; - public SpineObjectData41(string skelPath, string atlasPath) : base(skelPath, atlasPath) + public SpineObjectData41(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader) + : base(skelPath, atlasPath, textureLoader) { // 加载 atlas - try { _atlas = new Atlas(atlasPath, _textureLoader); } + try { _atlas = new Atlas(atlasPath, textureLoader); } catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); } // 加载 skel diff --git a/Spine/Implementations/SpineWrappers/V42/SpineObjectData42.cs b/Spine/Implementations/SpineWrappers/V42/SpineObjectData42.cs index acd41ee..83a7365 100644 --- a/Spine/Implementations/SpineWrappers/V42/SpineObjectData42.cs +++ b/Spine/Implementations/SpineWrappers/V42/SpineObjectData42.cs @@ -26,10 +26,11 @@ namespace Spine.Implementations.SpineWrappers.V42 private readonly ImmutableArray _animations; private readonly FrozenDictionary _animationsByName; - public SpineObjectData42(string skelPath, string atlasPath) : base(skelPath, atlasPath) + public SpineObjectData42(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader) + : base(skelPath, atlasPath, textureLoader) { // 加载 atlas - try { _atlas = new Atlas(atlasPath, _textureLoader); } + try { _atlas = new Atlas(atlasPath, textureLoader); } catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); } // 加载 skel diff --git a/Spine/SpineObject.cs b/Spine/SpineObject.cs index 1c13496..d270488 100644 --- a/Spine/SpineObject.cs +++ b/Spine/SpineObject.cs @@ -45,10 +45,12 @@ namespace Spine /// skel 文件路径 /// atlas 文件路径, 为空时会根据 进行自动检测 /// 要使用的运行时版本, 为空时会自动检测 - public SpineObject(string skelPath, string? atlasPath = null, SpineVersion? version = null) + public SpineObject(string skelPath, string? atlasPath = null, SpineVersion? version = null, TextureLoader? textureLoader = null) { if (string.IsNullOrWhiteSpace(skelPath)) throw new ArgumentException(skelPath, nameof(skelPath)); if (!File.Exists(skelPath)) throw new FileNotFoundException($"{nameof(skelPath)} not found", skelPath); + textureLoader ??= TextureLoader.DefaultLoader; + SkelPath = Path.GetFullPath(skelPath); AssetsDir = Directory.GetParent(skelPath).FullName; Name = Path.GetFileNameWithoutExtension(skelPath); @@ -91,7 +93,7 @@ namespace Spine { try { - _data = SpineObjectData.New(v, skelPath, atlasPath); + _data = SpineObjectData.New(v, skelPath, atlasPath, textureLoader); Version = v; break; } @@ -109,7 +111,7 @@ namespace Spine { // 根据版本实例化对象 Version = version; - _data = SpineObjectData.New(Version, skelPath, atlasPath); + _data = SpineObjectData.New(Version, skelPath, atlasPath, textureLoader); } // 创建状态实例 diff --git a/Spine/SpineWrappers/SpineObjectData.cs b/Spine/SpineWrappers/SpineObjectData.cs index a6c8e2a..0e8f0dc 100644 --- a/Spine/SpineWrappers/SpineObjectData.cs +++ b/Spine/SpineWrappers/SpineObjectData.cs @@ -20,18 +20,13 @@ namespace Spine.SpineWrappers /// /// 构建版本对象 /// - public static SpineObjectData New(SpineVersion version, string skelPath, string atlasPath) => CreateInstance(version.Tag, skelPath, atlasPath); - - /// - /// 纹理加载器, 可以设置一些预置参数 - /// - public static TextureLoader TextureLoader => _textureLoader; - protected static readonly TextureLoader _textureLoader = new(); + public static SpineObjectData New(SpineVersion version, string skelPath, string atlasPath, TextureLoader textureLoader) + => CreateInstance(version.Tag, skelPath, atlasPath, textureLoader); /// /// 构造函数, 继承的子类应当实现一个相同签名的构造函数 /// - public SpineObjectData(string skelPath, string atlasPath) { } + public SpineObjectData(string skelPath, string atlasPath, TextureLoader textureLoader) { } public abstract string SkeletonVersion { get; } diff --git a/Spine/SpineWrappers/TextureLoader.cs b/Spine/SpineWrappers/TextureLoader.cs index 9aebcff..c07654d 100644 --- a/Spine/SpineWrappers/TextureLoader.cs +++ b/Spine/SpineWrappers/TextureLoader.cs @@ -19,23 +19,62 @@ namespace Spine.SpineWrappers SpineRuntime42.TextureLoader { /// - /// 强制启用 Smooth + /// 默认的全局纹理加载器 /// - public bool ForceSmooth { get; set; } = false; + public static TextureLoader DefaultLoader { get; } = new(); /// - /// 强制启用 Repeated + /// 在读取纹理时强制进行通道预乘操作 /// - public bool ForceRepeated { get; set; } = false; + public bool ForcePremul { get; set; } = false; + + /// + /// 强制使用 Nearest + /// + public bool ForceNearest { get; set; } = false; /// /// 强制启用 Mipmap /// public bool ForceMipmap { get; set; } = false; - public void Load(SpineRuntime21.AtlasPage page, string path) + private SFML.Graphics.Texture ReadTexture(string path) { - var texture = new SFML.Graphics.Texture(path); + if (ForcePremul) + { + using var image = new SFML.Graphics.Image(path); + var width = image.Size.X; + var height = image.Size.Y; + var pixels = image.Pixels; + var size = width * height * 4; + for (int i = 0; i < size; i += 4) + { + byte a = pixels[i + 3]; + if (a == 0) + { + pixels[i + 0] = 0; + pixels[i + 1] = 0; + pixels[i + 2] = 0; + } + else if (a != 255) + { + float f = a / 255f; + pixels[i + 0] = (byte)(pixels[i + 0] * f); + pixels[i + 1] = (byte)(pixels[i + 1] * f); + pixels[i + 2] = (byte)(pixels[i + 2] * f); + } + } + var tex = new SFML.Graphics.Texture(width, height); + tex.Update(pixels); + return tex; + } + return new(path); + } + + public virtual void Load(SpineRuntime21.AtlasPage page, string path) + { + var texture = ReadTexture(path); + if (page.magFilter == SpineRuntime21.TextureFilter.Linear) { texture.Smooth = true; @@ -61,16 +100,16 @@ namespace Spine.SpineWrappers break; } - if (ForceSmooth) texture.Smooth = true; - if (ForceRepeated) texture.Repeated = true; + if (ForceNearest) texture.Smooth = false; if (ForceMipmap) texture.GenerateMipmap(); page.rendererObject = texture; } - public void Load(SpineRuntime36.AtlasPage page, string path) + public virtual void Load(SpineRuntime36.AtlasPage page, string path) { - var texture = new SFML.Graphics.Texture(path); + var texture = ReadTexture(path); + if (page.magFilter == SpineRuntime36.TextureFilter.Linear) { texture.Smooth = true; @@ -96,16 +135,16 @@ namespace Spine.SpineWrappers break; } - if (ForceSmooth) texture.Smooth = true; - if (ForceRepeated) texture.Repeated = true; + if (ForceNearest) texture.Smooth = false; if (ForceMipmap) texture.GenerateMipmap(); page.rendererObject = texture; } - public void Load(SpineRuntime37.AtlasPage page, string path) + public virtual void Load(SpineRuntime37.AtlasPage page, string path) { - var texture = new SFML.Graphics.Texture(path); + var texture = ReadTexture(path); + if (page.magFilter == SpineRuntime37.TextureFilter.Linear) { texture.Smooth = true; @@ -131,16 +170,16 @@ namespace Spine.SpineWrappers break; } - if (ForceSmooth) texture.Smooth = true; - if (ForceRepeated) texture.Repeated = true; + if (ForceNearest) texture.Smooth = false; if (ForceMipmap) texture.GenerateMipmap(); page.rendererObject = texture; } - public void Load(SpineRuntime38.AtlasPage page, string path) + public virtual void Load(SpineRuntime38.AtlasPage page, string path) { - var texture = new SFML.Graphics.Texture(path); + var texture = ReadTexture(path); + if (page.magFilter == SpineRuntime38.TextureFilter.Linear) { texture.Smooth = true; @@ -166,16 +205,20 @@ namespace Spine.SpineWrappers break; } - if (ForceSmooth) texture.Smooth = true; - if (ForceRepeated) texture.Repeated = true; + if (ForceNearest) texture.Smooth = false; if (ForceMipmap) texture.GenerateMipmap(); page.rendererObject = texture; + + // 似乎是不需要设置的, 因为存在某些 png 和 atlas 大小不同的情况, 一般是有一些缩放, 如果设置了反而渲染异常 + // page.width = (int)texture.Size.X; + // page.height = (int)texture.Size.Y; } - public void Load(SpineRuntime40.AtlasPage page, string path) + public virtual void Load(SpineRuntime40.AtlasPage page, string path) { - var texture = new SFML.Graphics.Texture(path); + var texture = ReadTexture(path); + if (page.magFilter == SpineRuntime40.TextureFilter.Linear) { texture.Smooth = true; @@ -201,16 +244,16 @@ namespace Spine.SpineWrappers break; } - if (ForceSmooth) texture.Smooth = true; - if (ForceRepeated) texture.Repeated = true; + if (ForceNearest) texture.Smooth = false; if (ForceMipmap) texture.GenerateMipmap(); page.rendererObject = texture; } - public void Load(SpineRuntime41.AtlasPage page, string path) + public virtual void Load(SpineRuntime41.AtlasPage page, string path) { - var texture = new SFML.Graphics.Texture(path); + var texture = ReadTexture(path); + if (page.magFilter == SpineRuntime41.TextureFilter.Linear) { texture.Smooth = true; @@ -236,16 +279,16 @@ namespace Spine.SpineWrappers break; } - if (ForceSmooth) texture.Smooth = true; - if (ForceRepeated) texture.Repeated = true; + if (ForceNearest) texture.Smooth = false; if (ForceMipmap) texture.GenerateMipmap(); page.rendererObject = texture; } - public void Load(SpineRuntime42.AtlasPage page, string path) + public virtual void Load(SpineRuntime42.AtlasPage page, string path) { - var texture = new SFML.Graphics.Texture(path); + var texture = ReadTexture(path); + if (page.magFilter == SpineRuntime42.TextureFilter.Linear) { texture.Smooth = true; @@ -271,18 +314,13 @@ namespace Spine.SpineWrappers break; } - if (ForceSmooth) texture.Smooth = true; - if (ForceRepeated) texture.Repeated = true; + if (ForceNearest) texture.Smooth = false; if (ForceMipmap) texture.GenerateMipmap(); page.rendererObject = texture; - - // 似乎是不需要设置的, 因为存在某些 png 和 atlas 大小不同的情况, 一般是有一些缩放, 如果设置了反而渲染异常 - // page.width = (int)texture.Size.X; - // page.height = (int)texture.Size.Y; } - public void Unload(object texture) + public virtual void Unload(object texture) { ((SFML.Graphics.Texture)texture).Dispose(); }