预修改适配对多轨道动画
This commit is contained in:
@@ -607,7 +607,7 @@ namespace SpineViewer.Controls
|
|||||||
lock (SpineListView.Spines)
|
lock (SpineListView.Spines)
|
||||||
{
|
{
|
||||||
foreach (var spine in SpineListView.Spines)
|
foreach (var spine in SpineListView.Spines)
|
||||||
spine.CurrentAnimation = spine.CurrentAnimation;
|
spine.Track0Animation = spine.Track0Animation; // TODO: 多轨道重置
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -619,7 +619,7 @@ namespace SpineViewer.Controls
|
|||||||
lock (SpineListView.Spines)
|
lock (SpineListView.Spines)
|
||||||
{
|
{
|
||||||
foreach (var spine in SpineListView.Spines)
|
foreach (var spine in SpineListView.Spines)
|
||||||
spine.CurrentAnimation = spine.CurrentAnimation;
|
spine.Track0Animation = spine.Track0Animation; // TODO: 多轨道重置
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IsUpdating = true;
|
IsUpdating = true;
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ namespace SpineViewer.Exporter.Implementations.Exporter
|
|||||||
{
|
{
|
||||||
var args = (VideoExportArgs)ExportArgs;
|
var args = (VideoExportArgs)ExportArgs;
|
||||||
|
|
||||||
// 独立导出时如果 args.Duration 小于 0 则使用自己的动画时长
|
// 独立导出时如果 args.Duration 小于 0 则使用 Track0 的动画时长
|
||||||
var duration = args.Duration;
|
var duration = args.Duration;
|
||||||
if (duration < 0) duration = spine.CurrentAnimationDuration;
|
if (duration < 0) duration = spine.GetAnimationDuration(spine.Track0Animation); // TODO: 也许可以使用所有轨道的最大值
|
||||||
|
|
||||||
float delta = 1f / args.FPS;
|
float delta = 1f / args.FPS;
|
||||||
int total = Math.Max(1, (int)(duration * args.FPS)); // 至少导出 1 帧
|
int total = Math.Max(1, (int)(duration * args.FPS)); // 至少导出 1 帧
|
||||||
@@ -75,7 +75,7 @@ namespace SpineViewer.Exporter.Implementations.Exporter
|
|||||||
public override void Export(Spine.Spine[] spines, BackgroundWorker? worker = null)
|
public override void Export(Spine.Spine[] spines, BackgroundWorker? worker = null)
|
||||||
{
|
{
|
||||||
// 导出视频格式需要把模型时间都重置到 0
|
// 导出视频格式需要把模型时间都重置到 0
|
||||||
foreach (var spine in spines) spine.CurrentAnimation = spine.CurrentAnimation;
|
foreach (var spine in spines) spine.Track0Animation = spine.Track0Animation; // TODO: 多轨道重置
|
||||||
base.Export(spines, worker);
|
base.Export(spines, worker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,10 +82,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
|
|
||||||
foreach (var anime in skeletonData.Animations)
|
foreach (var anime in skeletonData.Animations)
|
||||||
animationNames.Add(anime.Name);
|
animationNames.Add(anime.Name);
|
||||||
|
|
||||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
|
||||||
CurrentAnimation = animationNames.Last();
|
|
||||||
CurrentSkin = skinNames.Last();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
@@ -113,8 +109,8 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
var position = Position;
|
var position = Position;
|
||||||
var flipX = FlipX;
|
var flipX = FlipX;
|
||||||
var flipY = FlipY;
|
var flipY = FlipY;
|
||||||
var animation = CurrentAnimation;
|
var animation = Track0Animation; // TODO: 适配多轨道
|
||||||
var skin = CurrentSkin;
|
var skin = Skin;
|
||||||
|
|
||||||
var val = Math.Max(value, SCALE_MIN);
|
var val = Math.Max(value, SCALE_MIN);
|
||||||
if (skeletonBinary is not null)
|
if (skeletonBinary is not null)
|
||||||
@@ -137,8 +133,8 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
Position = position;
|
Position = position;
|
||||||
FlipX = flipX;
|
FlipX = flipX;
|
||||||
FlipY = flipY;
|
FlipY = flipY;
|
||||||
CurrentAnimation = animation;
|
Track0Animation = animation; // TODO: 适配多轨道
|
||||||
CurrentSkin = skin;
|
Skin = skin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +161,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
set { skeleton.FlipY = value; Update(0); }
|
set { skeleton.FlipY = value; Update(0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentAnimation
|
public override string Skin
|
||||||
|
{
|
||||||
|
get => skeleton.Skin?.Name ?? "default";
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!skinNames.Contains(value)) return;
|
||||||
|
skeleton.SetSkin(value);
|
||||||
|
skeleton.SetSlotsToSetupPose();
|
||||||
|
Update(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Track0Animation
|
||||||
{
|
{
|
||||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||||
set
|
set
|
||||||
@@ -178,18 +186,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentSkin
|
|
||||||
{
|
|
||||||
get => skeleton.Skin?.Name ?? "default";
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (!skinNames.Contains(value)) return;
|
|
||||||
skeleton.SetSkin(value);
|
|
||||||
skeleton.SetSlotsToSetupPose();
|
|
||||||
Update(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override RectangleF Bounds
|
public override RectangleF Bounds
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -81,10 +81,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
|
|
||||||
foreach (var anime in skeletonData.Animations)
|
foreach (var anime in skeletonData.Animations)
|
||||||
animationNames.Add(anime.Name);
|
animationNames.Add(anime.Name);
|
||||||
|
|
||||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
|
||||||
CurrentAnimation = animationNames.Last();
|
|
||||||
CurrentSkin = skinNames.Last();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
@@ -112,8 +108,8 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
var position = Position;
|
var position = Position;
|
||||||
var flipX = FlipX;
|
var flipX = FlipX;
|
||||||
var flipY = FlipY;
|
var flipY = FlipY;
|
||||||
var animation = CurrentAnimation;
|
var animation = Track0Animation; // TODO: 适配多轨道
|
||||||
var skin = CurrentSkin;
|
var skin = Skin;
|
||||||
|
|
||||||
var val = Math.Max(value, SCALE_MIN);
|
var val = Math.Max(value, SCALE_MIN);
|
||||||
if (skeletonBinary is not null)
|
if (skeletonBinary is not null)
|
||||||
@@ -136,8 +132,8 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
Position = position;
|
Position = position;
|
||||||
FlipX = flipX;
|
FlipX = flipX;
|
||||||
FlipY = flipY;
|
FlipY = flipY;
|
||||||
CurrentAnimation = animation;
|
Track0Animation = animation; // TODO: 适配多轨道
|
||||||
CurrentSkin = skin;
|
Skin = skin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +160,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
set { skeleton.FlipY = value; Update(0); }
|
set { skeleton.FlipY = value; Update(0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentAnimation
|
public override string Skin
|
||||||
|
{
|
||||||
|
get => skeleton.Skin?.Name ?? "default";
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!skinNames.Contains(value)) return;
|
||||||
|
skeleton.SetSkin(value);
|
||||||
|
skeleton.SetSlotsToSetupPose();
|
||||||
|
Update(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Track0Animation
|
||||||
{
|
{
|
||||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||||
set
|
set
|
||||||
@@ -177,18 +185,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentSkin
|
|
||||||
{
|
|
||||||
get => skeleton.Skin?.Name ?? "default";
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (!skinNames.Contains(value)) return;
|
|
||||||
skeleton.SetSkin(value);
|
|
||||||
skeleton.SetSlotsToSetupPose();
|
|
||||||
Update(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override RectangleF Bounds
|
public override RectangleF Bounds
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -79,10 +79,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
|
|
||||||
foreach (var anime in skeletonData.Animations)
|
foreach (var anime in skeletonData.Animations)
|
||||||
animationNames.Add(anime.Name);
|
animationNames.Add(anime.Name);
|
||||||
|
|
||||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
|
||||||
CurrentAnimation = animationNames.Last();
|
|
||||||
CurrentSkin = skinNames.Last();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
@@ -137,7 +133,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentAnimation
|
public override string Skin
|
||||||
|
{
|
||||||
|
get => skeleton.Skin?.Name ?? "default";
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!skinNames.Contains(value)) return;
|
||||||
|
skeleton.SetSkin(value);
|
||||||
|
skeleton.SetSlotsToSetupPose();
|
||||||
|
Update(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Track0Animation
|
||||||
{
|
{
|
||||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||||
set
|
set
|
||||||
@@ -150,18 +158,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentSkin
|
|
||||||
{
|
|
||||||
get => skeleton.Skin?.Name ?? "default";
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (!skinNames.Contains(value)) return;
|
|
||||||
skeleton.SetSkin(value);
|
|
||||||
skeleton.SetSlotsToSetupPose();
|
|
||||||
Update(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override RectangleF Bounds
|
public override RectangleF Bounds
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -85,10 +85,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
|
|
||||||
foreach (var anime in skeletonData.Animations)
|
foreach (var anime in skeletonData.Animations)
|
||||||
animationNames.Add(anime.Name);
|
animationNames.Add(anime.Name);
|
||||||
|
|
||||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
|
||||||
CurrentAnimation = animationNames.Last();
|
|
||||||
CurrentSkin = skinNames.Last();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
@@ -143,7 +139,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentAnimation
|
public override string Skin
|
||||||
|
{
|
||||||
|
get => skeleton.Skin?.Name ?? "default";
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!skinNames.Contains(value)) return;
|
||||||
|
skeleton.SetSkin(value);
|
||||||
|
skeleton.SetSlotsToSetupPose();
|
||||||
|
Update(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Track0Animation
|
||||||
{
|
{
|
||||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||||
set
|
set
|
||||||
@@ -156,18 +164,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentSkin
|
|
||||||
{
|
|
||||||
get => skeleton.Skin?.Name ?? "default";
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (!skinNames.Contains(value)) return;
|
|
||||||
skeleton.SetSkin(value);
|
|
||||||
skeleton.SetSlotsToSetupPose();
|
|
||||||
Update(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override RectangleF Bounds
|
public override RectangleF Bounds
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -81,10 +81,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
|
|
||||||
foreach (var anime in skeletonData.Animations)
|
foreach (var anime in skeletonData.Animations)
|
||||||
animationNames.Add(anime.Name);
|
animationNames.Add(anime.Name);
|
||||||
|
|
||||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
|
||||||
CurrentAnimation = animationNames.Last();
|
|
||||||
CurrentSkin = skinNames.Last();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
@@ -139,7 +135,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentAnimation
|
public override string Skin
|
||||||
|
{
|
||||||
|
get => skeleton.Skin?.Name ?? "default";
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!skinNames.Contains(value)) return;
|
||||||
|
skeleton.SetSkin(value);
|
||||||
|
skeleton.SetSlotsToSetupPose();
|
||||||
|
Update(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Track0Animation
|
||||||
{
|
{
|
||||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||||
set
|
set
|
||||||
@@ -152,18 +160,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentSkin
|
|
||||||
{
|
|
||||||
get => skeleton.Skin?.Name ?? "default";
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (!skinNames.Contains(value)) return;
|
|
||||||
skeleton.SetSkin(value);
|
|
||||||
skeleton.SetSlotsToSetupPose();
|
|
||||||
Update(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override RectangleF Bounds
|
public override RectangleF Bounds
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -81,10 +81,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
|
|
||||||
foreach (var anime in skeletonData.Animations)
|
foreach (var anime in skeletonData.Animations)
|
||||||
animationNames.Add(anime.Name);
|
animationNames.Add(anime.Name);
|
||||||
|
|
||||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
|
||||||
CurrentAnimation = animationNames.Last();
|
|
||||||
CurrentSkin = skinNames.Last();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
@@ -139,7 +135,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentAnimation
|
public override string Skin
|
||||||
|
{
|
||||||
|
get => skeleton.Skin?.Name ?? "default";
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!skinNames.Contains(value)) return;
|
||||||
|
skeleton.SetSkin(value);
|
||||||
|
skeleton.SetSlotsToSetupPose();
|
||||||
|
Update(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Track0Animation
|
||||||
{
|
{
|
||||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||||
set
|
set
|
||||||
@@ -152,18 +160,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentSkin
|
|
||||||
{
|
|
||||||
get => skeleton.Skin?.Name ?? "default";
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (!skinNames.Contains(value)) return;
|
|
||||||
skeleton.SetSkin(value);
|
|
||||||
skeleton.SetSlotsToSetupPose();
|
|
||||||
Update(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override RectangleF Bounds
|
public override RectangleF Bounds
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -81,10 +81,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
|
|
||||||
foreach (var anime in skeletonData.Animations)
|
foreach (var anime in skeletonData.Animations)
|
||||||
animationNames.Add(anime.Name);
|
animationNames.Add(anime.Name);
|
||||||
|
|
||||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
|
||||||
CurrentAnimation = animationNames.Last();
|
|
||||||
CurrentSkin = skinNames.Last();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
@@ -139,7 +135,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentAnimation
|
public override string Skin
|
||||||
|
{
|
||||||
|
get => skeleton.Skin?.Name ?? "default";
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!skinNames.Contains(value)) return;
|
||||||
|
skeleton.SetSkin(value);
|
||||||
|
skeleton.SetSlotsToSetupPose();
|
||||||
|
Update(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Track0Animation
|
||||||
{
|
{
|
||||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||||
set
|
set
|
||||||
@@ -152,18 +160,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CurrentSkin
|
|
||||||
{
|
|
||||||
get => skeleton.Skin?.Name ?? "default";
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (!skinNames.Contains(value)) return;
|
|
||||||
skeleton.SetSkin(value);
|
|
||||||
skeleton.SetSlotsToSetupPose();
|
|
||||||
Update(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override RectangleF Bounds
|
public override RectangleF Bounds
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -182,7 +182,38 @@ namespace SpineViewer.Spine
|
|||||||
{
|
{
|
||||||
throw new NotImplementedException($"Not implemented version: {version}");
|
throw new NotImplementedException($"Not implemented version: {version}");
|
||||||
}
|
}
|
||||||
return (Spine)Activator.CreateInstance(spineType, skelPath, atlasPath);
|
|
||||||
|
var spine = (Spine)Activator.CreateInstance(spineType, skelPath, atlasPath);
|
||||||
|
|
||||||
|
// 统一初始化
|
||||||
|
spine.initBounds = spine.Bounds;
|
||||||
|
|
||||||
|
// XXX: tex 没办法在这里主动 Dispose
|
||||||
|
// 批量添加在获取预览图的时候极大概率会和预览线程死锁
|
||||||
|
// 虽然两边不会同时调用 Draw, 但是死锁似乎和 Draw 函数有关
|
||||||
|
// 除此之外, 似乎还和 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.Clear(SFML.Graphics.Color.Transparent);
|
||||||
|
tex.Draw(spine);
|
||||||
|
tex.Display();
|
||||||
|
|
||||||
|
using (var img = tex.Texture.CopyToImage())
|
||||||
|
{
|
||||||
|
img.SaveToMemory(out var imgBuffer, "bmp");
|
||||||
|
using (var stream = new MemoryStream(imgBuffer))
|
||||||
|
{
|
||||||
|
// 必须重复构造一个副本才能摆脱对流的依赖, 否则之后使用会报错
|
||||||
|
spine.preview = new Bitmap(new Bitmap(stream));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||||
|
spine.Skin = spine.SkinNames.Last();
|
||||||
|
spine.Track0Animation = spine.AnimationNames.Last();
|
||||||
|
|
||||||
|
return spine;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -300,26 +331,6 @@ namespace SpineViewer.Spine
|
|||||||
|
|
||||||
#region 属性 | [3] 动画
|
#region 属性 | [3] 动画
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 包含的所有动画名称
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
public ReadOnlyCollection<string> AnimationNames { get => animationNames.AsReadOnly(); }
|
|
||||||
protected List<string> animationNames = [EMPTY_ANIMATION];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前动画名称, 如果设置的动画不存在则忽略
|
|
||||||
/// </summary>
|
|
||||||
[TypeConverter(typeof(AnimationConverter))]
|
|
||||||
[Category("[3] 动画"), DisplayName("当前动画")]
|
|
||||||
public abstract string CurrentAnimation { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前动画时长
|
|
||||||
/// </summary>
|
|
||||||
[Category("[3] 动画"), DisplayName("当前动画时长")]
|
|
||||||
public float CurrentAnimationDuration { get => GetAnimationDuration(CurrentAnimation); }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 包含的所有皮肤名称
|
/// 包含的所有皮肤名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -328,11 +339,31 @@ namespace SpineViewer.Spine
|
|||||||
protected List<string> skinNames = [];
|
protected List<string> skinNames = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前皮肤名称, 如果设置的皮肤不存在则忽略
|
/// 使用的皮肤名称, 如果设置的皮肤不存在则忽略
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TypeConverter(typeof(SkinConverter))]
|
[TypeConverter(typeof(SkinConverter))]
|
||||||
[Category("[3] 动画"), DisplayName("当前皮肤")]
|
[Category("[3] 动画"), DisplayName("皮肤")]
|
||||||
public abstract string CurrentSkin { get; set; }
|
public abstract string Skin { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 包含的所有动画名称
|
||||||
|
/// </summary>
|
||||||
|
[Browsable(false)]
|
||||||
|
public ReadOnlyCollection<string> AnimationNames { get => animationNames.AsReadOnly(); }
|
||||||
|
protected List<string> animationNames = [EMPTY_ANIMATION];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 默认轨道动画名称, 如果设置的动画不存在则忽略
|
||||||
|
/// </summary>
|
||||||
|
[TypeConverter(typeof(AnimationConverter))]
|
||||||
|
[Category("[3] 动画"), DisplayName("默认轨道动画")]
|
||||||
|
public abstract string Track0Animation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 默认轨道动画时长
|
||||||
|
/// </summary>
|
||||||
|
[Category("[3] 动画"), DisplayName("默认轨道动画时长")]
|
||||||
|
public float Track0AnimationDuration { get => GetAnimationDuration(Track0Animation); } // TODO: 动画时长变成伪属性在面板显示
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -395,55 +426,15 @@ namespace SpineViewer.Spine
|
|||||||
/// 初始状态下的骨骼包围盒
|
/// 初始状态下的骨骼包围盒
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Browsable(false)]
|
[Browsable(false)]
|
||||||
public RectangleF InitBounds
|
public RectangleF InitBounds { get => initBounds; }
|
||||||
{
|
private RectangleF initBounds;
|
||||||
get
|
|
||||||
{
|
|
||||||
if (initBounds is null)
|
|
||||||
{
|
|
||||||
var tmp = CurrentAnimation;
|
|
||||||
CurrentAnimation = EMPTY_ANIMATION;
|
|
||||||
initBounds = Bounds;
|
|
||||||
CurrentAnimation = tmp;
|
|
||||||
}
|
|
||||||
return (RectangleF)initBounds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private RectangleF? initBounds = null;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 骨骼预览图
|
/// 骨骼预览图
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Browsable(false)]
|
[Browsable(false)]
|
||||||
public Image Preview
|
public Image Preview { get => preview; }
|
||||||
{
|
private Image preview;
|
||||||
get
|
|
||||||
{
|
|
||||||
if (preview is null)
|
|
||||||
{
|
|
||||||
// XXX: tex 没办法在这里主动 Dispose
|
|
||||||
// 批量添加在获取预览图的时候极大概率会和预览线程死锁
|
|
||||||
// 虽然两边不会同时调用 Draw, 但是死锁似乎和 Draw 函数有关
|
|
||||||
// 除此之外, 似乎还和 tex 的 Dispose 有关
|
|
||||||
// 如果不对 tex 进行 Dispose, 那么不管是否 Draw 都正常不会死锁
|
|
||||||
var tex = new SFML.Graphics.RenderTexture(PREVIEW_WIDTH, PREVIEW_HEIGHT);
|
|
||||||
tex.SetView(InitBounds.GetView(PREVIEW_WIDTH, PREVIEW_HEIGHT));
|
|
||||||
tex.Clear(SFML.Graphics.Color.Transparent);
|
|
||||||
var tmp = CurrentAnimation;
|
|
||||||
CurrentAnimation = EMPTY_ANIMATION;
|
|
||||||
tex.Draw(this);
|
|
||||||
CurrentAnimation = tmp;
|
|
||||||
tex.Display();
|
|
||||||
|
|
||||||
using var img = tex.Texture.CopyToImage();
|
|
||||||
img.SaveToMemory(out var imgBuffer, "bmp");
|
|
||||||
using var stream = new MemoryStream(imgBuffer);
|
|
||||||
preview = new Bitmap(new Bitmap(stream)); // 必须重复构造一个副本才能摆脱对流的依赖, 否则之后使用会报错
|
|
||||||
}
|
|
||||||
return preview;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private Image preview = null;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取动画时长, 如果动画不存在则返回 0
|
/// 获取动画时长, 如果动画不存在则返回 0
|
||||||
|
|||||||
Reference in New Issue
Block a user