Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
479a5e4da9 | ||
|
|
4829454877 | ||
|
|
28664f6387 | ||
|
|
1a08a23a9c | ||
|
|
16f344ff1b | ||
|
|
693ce0e2e8 | ||
|
|
e6f533ea65 | ||
|
|
fcc21d63b0 | ||
|
|
afc0ffcb67 | ||
|
|
9ffb9840e1 | ||
|
|
4766ccf1b6 | ||
|
|
16b75c80a3 | ||
|
|
880f063046 | ||
|
|
723c11b886 | ||
|
|
5e074b1cf7 | ||
|
|
71d2fee36e | ||
|
|
7dc701464f | ||
|
|
fd876ef90f | ||
|
|
0597852178 | ||
|
|
81b1333091 | ||
|
|
7baebd79a6 |
19
CHANGELOG.md
19
CHANGELOG.md
@@ -1,5 +1,24 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v0.11.3
|
||||
|
||||
- 增加模型隐藏设置属性
|
||||
- 加宽面板分割条 (4 -> 8 像素)
|
||||
- 优化属性面板分组显示
|
||||
- 增加调试纹理
|
||||
|
||||
## v0.11.2
|
||||
|
||||
- 增加皮肤切换
|
||||
- 优化模型缩放实现
|
||||
- 修复部分情况纹理加载异常
|
||||
|
||||
## v0.11.1
|
||||
|
||||
- 增加 GIF 导出格式
|
||||
- 增加逐个导出时可选自动时长
|
||||
- 优化使用体验
|
||||
|
||||
## v0.11.0
|
||||
|
||||
- 完成导出系统, 支持完整的单帧和帧序列导出功能
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
Below is the translated English version of your README:
|
||||
|
||||
---
|
||||
|
||||
# [SpineViewer](https://github.com/ww-rm/SpineViewer)
|
||||
|
||||
[](https://github.com/ww-rm/SpineViewer/actions/workflows/dotnet-desktop.yml)
|
||||
@@ -98,4 +94,4 @@ For more detailed instructions and usage, please refer to the [Wiki](https://git
|
||||
|
||||
*If you like this project, please give it a :star: and share it with others! :)*
|
||||
|
||||
[](https://starchart.cc/ww-rm/SpineViewer)
|
||||
[](https://starchart.cc/ww-rm/SpineViewer)
|
||||
|
||||
@@ -12,7 +12,6 @@ using SpineViewer.Spine;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace SpineViewer.Controls
|
||||
{
|
||||
public partial class SpineListView : UserControl
|
||||
@@ -166,14 +165,20 @@ namespace SpineViewer.Controls
|
||||
worker.ReportProgress((int)((i + 1) * 100.0) / totalCount, $"已处理 {i + 1}/{totalCount}");
|
||||
}
|
||||
|
||||
// 选中最后一项
|
||||
listView.Invoke(() =>
|
||||
{
|
||||
if (listView.Items.Count > 0)
|
||||
{
|
||||
listView.SelectedIndices.Clear();
|
||||
listView.SelectedIndices.Add(listView.Items.Count - 1);
|
||||
}
|
||||
});
|
||||
|
||||
if (error > 0)
|
||||
{
|
||||
Program.Logger.Warn("Batch load {} successfully, {} failed", success, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
Program.Logger.Info("{} skel loaded successfully", success);
|
||||
}
|
||||
|
||||
Program.LogCurrentMemoryUsage();
|
||||
}
|
||||
|
||||
@@ -54,32 +54,32 @@ namespace SpineViewer.Controls
|
||||
private class PreviewerProperty(SpinePreviewer previewer)
|
||||
{
|
||||
[TypeConverter(typeof(SizeConverter))]
|
||||
[Category("导出"), DisplayName("分辨率")]
|
||||
[Category("[0] 导出"), DisplayName("分辨率")]
|
||||
public Size Resolution { get => previewer.Resolution; set => previewer.Resolution = value; }
|
||||
|
||||
[TypeConverter(typeof(PointFConverter))]
|
||||
[Category("导出"), DisplayName("画面中心点")]
|
||||
[Category("[0] 导出"), DisplayName("画面中心点")]
|
||||
public PointF Center { get => previewer.Center; set => previewer.Center = value; }
|
||||
|
||||
[Category("导出"), DisplayName("缩放")]
|
||||
[Category("[0] 导出"), DisplayName("缩放")]
|
||||
public float Zoom { get => previewer.Zoom; set => previewer.Zoom = value; }
|
||||
|
||||
[Category("导出"), DisplayName("旋转")]
|
||||
[Category("[0] 导出"), DisplayName("旋转")]
|
||||
public float Rotation { get => previewer.Rotation; set => previewer.Rotation = value; }
|
||||
|
||||
[Category("导出"), DisplayName("水平翻转")]
|
||||
[Category("[0] 导出"), DisplayName("水平翻转")]
|
||||
public bool FlipX { get => previewer.FlipX; set => previewer.FlipX = value; }
|
||||
|
||||
[Category("导出"), DisplayName("垂直翻转")]
|
||||
[Category("[0] 导出"), DisplayName("垂直翻转")]
|
||||
public bool FlipY { get => previewer.FlipY; set => previewer.FlipY = value; }
|
||||
|
||||
[Category("导出"), DisplayName("仅渲染选中")]
|
||||
[Category("[0] 导出"), DisplayName("仅渲染选中")]
|
||||
public bool RenderSelectedOnly { get => previewer.RenderSelectedOnly; set => previewer.RenderSelectedOnly = value; }
|
||||
|
||||
[Category("预览"), DisplayName("显示坐标轴")]
|
||||
[Category("[1] 预览"), DisplayName("显示坐标轴")]
|
||||
public bool ShowAxis { get => previewer.ShowAxis; set => previewer.ShowAxis = value; }
|
||||
|
||||
[Category("预览"), DisplayName("最大帧率")]
|
||||
[Category("[1] 预览"), DisplayName("最大帧率")]
|
||||
public uint MaxFps { get => previewer.MaxFps; set => previewer.MaxFps = value; }
|
||||
}
|
||||
|
||||
@@ -371,6 +371,16 @@ namespace SpineViewer.Controls
|
||||
delta = Clock.ElapsedTime.AsSeconds();
|
||||
Clock.Restart();
|
||||
|
||||
// 停止更新的时候只是时间不前进, 但是坐标变换还是要更新, 否则无法移动对象
|
||||
if (!IsUpdating) delta = 0;
|
||||
|
||||
// 加上要快进的量
|
||||
lock (_forwardDeltaLock)
|
||||
{
|
||||
delta += forwardDelta;
|
||||
forwardDelta = 0;
|
||||
}
|
||||
|
||||
RenderWindow.Clear(BackgroundColor);
|
||||
|
||||
if (ShowAxis)
|
||||
@@ -389,24 +399,14 @@ namespace SpineViewer.Controls
|
||||
{
|
||||
lock (SpineListView.Spines)
|
||||
{
|
||||
var spines = SpineListView.Spines;
|
||||
for (int i = spines.Count - 1; i >= 0; i--)
|
||||
var spines = SpineListView.Spines.Where(sp => !sp.IsHidden).ToArray();
|
||||
for (int i = spines.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (cancelToken is not null && cancelToken.IsCancellationRequested)
|
||||
break; // 提前中止
|
||||
|
||||
var spine = spines[i];
|
||||
|
||||
// 停止更新的时候只是时间不前进, 但是坐标变换还是要更新, 否则无法移动对象
|
||||
if (!IsUpdating) delta = 0;
|
||||
|
||||
// 加上要快进的量
|
||||
lock (_forwardDeltaLock)
|
||||
{
|
||||
delta += forwardDelta;
|
||||
forwardDelta = 0;
|
||||
}
|
||||
|
||||
spine.Update(delta);
|
||||
|
||||
if (RenderSelectedOnly && !spine.IsSelected)
|
||||
@@ -487,9 +487,11 @@ namespace SpineViewer.Controls
|
||||
// 仅渲染选中模式禁止在画面里选择对象
|
||||
if (RenderSelectedOnly)
|
||||
{
|
||||
// 只在被选中的对象里判断是否有效命中
|
||||
bool hit = false;
|
||||
foreach (int i in SpineListView.SelectedIndices)
|
||||
{
|
||||
if (spines[i].IsHidden) continue;
|
||||
if (!spines[i].Bounds.Contains(src)) continue;
|
||||
hit = true;
|
||||
break;
|
||||
@@ -500,12 +502,13 @@ namespace SpineViewer.Controls
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有按下 Ctrl 键就只选中点击的那个, 所以先清空选中列表
|
||||
if ((ModifierKeys & Keys.Control) == 0)
|
||||
{
|
||||
// 没按 Ctrl 的情况下, 如果命中了已选中对象, 则就算普通命中
|
||||
bool hit = false;
|
||||
for (int i = 0; i < spines.Count; i++)
|
||||
{
|
||||
if (spines[i].IsHidden) continue;
|
||||
if (!spines[i].Bounds.Contains(src)) continue;
|
||||
|
||||
hit = true;
|
||||
@@ -524,10 +527,11 @@ namespace SpineViewer.Controls
|
||||
}
|
||||
else
|
||||
{
|
||||
// 按下 Ctrl 的情况就执行多选, 并且点空白处也不会清空选中
|
||||
for (int i = 0; i < spines.Count; i++)
|
||||
{
|
||||
if (!spines[i].Bounds.Contains(src))
|
||||
continue;
|
||||
if (spines[i].IsHidden) continue;
|
||||
if (!spines[i].Bounds.Contains(src)) continue;
|
||||
|
||||
SpineListView.SelectedIndices.Add(i);
|
||||
break;
|
||||
@@ -558,8 +562,12 @@ namespace SpineViewer.Controls
|
||||
{
|
||||
lock (SpineListView.Spines)
|
||||
{
|
||||
var spines = SpineListView.Spines;
|
||||
foreach (int i in SpineListView.SelectedIndices)
|
||||
SpineListView.Spines[i].Position += delta;
|
||||
{
|
||||
if (spines[i].IsHidden) continue;
|
||||
spines[i].Position += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
draggingSrc = dst;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace SpineViewer.Dialogs
|
||||
PropertyInfo? labelProp = category.GetType().GetProperty("Label", BindingFlags.Instance | BindingFlags.Public);
|
||||
if (labelProp == null) continue;
|
||||
string? label = labelProp.GetValue(category) as string;
|
||||
if (label != "导出") continue;
|
||||
if (label != "[0] 导出") continue;
|
||||
|
||||
// 获取该分组下的所有属性项
|
||||
PropertyInfo? gridItemsProp = category.GetType().GetProperty("GridItems", BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
@@ -60,32 +60,32 @@ namespace SpineViewer.Exporter
|
||||
/// 输出文件夹
|
||||
/// </summary>
|
||||
[Editor(typeof(FolderNameEditor), typeof(UITypeEditor))]
|
||||
[Category("导出"), DisplayName("输出文件夹"), Description("逐个导出时可以留空,将逐个导出到模型自身所在目录")]
|
||||
[Category("[0] 导出"), DisplayName("输出文件夹"), Description("逐个导出时可以留空,将逐个导出到模型自身所在目录")]
|
||||
public string? OutputDir { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 导出单个
|
||||
/// </summary>
|
||||
[Category("导出"), DisplayName("导出单个"), Description("是否将模型在同一个画面上导出单个文件,否则逐个导出模型")]
|
||||
[Category("[0] 导出"), DisplayName("导出单个"), Description("是否将模型在同一个画面上导出单个文件,否则逐个导出模型")]
|
||||
public bool ExportSingle { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 画面分辨率
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(SizeConverter))]
|
||||
[Category("导出"), DisplayName("分辨率"), Description("画面的宽高像素大小,请在预览画面参数面板进行调整")]
|
||||
[Category("[0] 导出"), DisplayName("分辨率"), Description("画面的宽高像素大小,请在预览画面参数面板进行调整")]
|
||||
public Size Resolution { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 渲染视窗
|
||||
/// </summary>
|
||||
[Category("导出"), DisplayName("视图"), Description("画面的视图参数,请在预览画面参数面板进行调整")]
|
||||
[Category("[0] 导出"), DisplayName("视图"), Description("画面的视图参数,请在预览画面参数面板进行调整")]
|
||||
public SFML.Graphics.View View { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否仅渲染选中
|
||||
/// </summary>
|
||||
[Category("导出"), DisplayName("仅渲染选中"), Description("是否仅导出选中的模型,请在预览画面参数面板进行调整")]
|
||||
[Category("[0] 导出"), DisplayName("仅渲染选中"), Description("是否仅导出选中的模型,请在预览画面参数面板进行调整")]
|
||||
public bool RenderSelectedOnly { get; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace SpineViewer.Exporter.Implementations.ExportArgs
|
||||
/// 单帧画面格式
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(ImageFormatConverter))]
|
||||
[Category("单帧画面"), DisplayName("图像格式")]
|
||||
[Category("[1] 单帧画面"), DisplayName("图像格式")]
|
||||
public ImageFormat ImageFormat
|
||||
{
|
||||
get => imageFormat;
|
||||
@@ -35,14 +35,14 @@ namespace SpineViewer.Exporter.Implementations.ExportArgs
|
||||
/// <summary>
|
||||
/// 文件名后缀
|
||||
/// </summary>
|
||||
[Category("单帧画面"), DisplayName("文件名后缀"), Description("与图像格式匹配的文件名后缀")]
|
||||
[Category("[1] 单帧画面"), DisplayName("文件名后缀"), Description("与图像格式匹配的文件名后缀")]
|
||||
public string FileSuffix { get => imageFormat.GetSuffix(); }
|
||||
|
||||
/// <summary>
|
||||
/// DPI
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(SizeFConverter))]
|
||||
[Category("单帧画面"), DisplayName("DPI"), Description("导出图像的每英寸像素数,用于调整图像的物理尺寸")]
|
||||
[Category("[1] 单帧画面"), DisplayName("DPI"), Description("导出图像的每英寸像素数,用于调整图像的物理尺寸")]
|
||||
public SizeF DPI
|
||||
{
|
||||
get => dpi;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace SpineViewer.Exporter.Implementations.ExportArgs
|
||||
/// 文件名后缀
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(SFMLImageFileSuffixConverter))]
|
||||
[Category("帧序列参数"), DisplayName("文件名后缀"), Description("帧文件的后缀,同时决定帧图像格式")]
|
||||
[Category("[2] 帧序列参数"), DisplayName("文件名后缀"), Description("帧文件的后缀,同时决定帧图像格式")]
|
||||
public string FileSuffix { get; set; } = ".png";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,14 @@ namespace SpineViewer.Exporter.Implementations.ExportArgs
|
||||
/// <summary>
|
||||
/// 调色板最大颜色数量
|
||||
/// </summary>
|
||||
[Category("GIF 参数"), DisplayName("调色板最大颜色数量"), Description("设置调色板使用的最大颜色数量, 越多则色彩保留程度越高")]
|
||||
[Category("[2] GIF 参数"), DisplayName("调色板最大颜色数量"), Description("设置调色板使用的最大颜色数量, 越多则色彩保留程度越高")]
|
||||
public uint MaxColors { get => maxColors; set => maxColors = Math.Clamp(value, 2, 256); }
|
||||
private uint maxColors = 256;
|
||||
|
||||
/// <summary>
|
||||
/// 透明度阈值
|
||||
/// </summary>
|
||||
[Category("GIF 参数"), DisplayName("透明度阈值"), Description("小于该值的像素点会被认为是透明像素")]
|
||||
[Category("[2] GIF 参数"), DisplayName("透明度阈值"), Description("小于该值的像素点会被认为是透明像素")]
|
||||
public byte AlphaThreshold { get => alphaThreshold; set => alphaThreshold = value; }
|
||||
private byte alphaThreshold = 128;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace SpineViewer.Exporter.Implementations.ExportArgs
|
||||
/// <summary>
|
||||
/// 导出时长
|
||||
/// </summary>
|
||||
[Category("视频参数"), DisplayName("时长"), Description("可以从模型列表查看动画时长, 如果小于 0, 则在逐个导出时每个模型使用各自的当前动画时长")]
|
||||
[Category("[1] 视频参数"), DisplayName("时长"), Description("可以从模型列表查看动画时长, 如果小于 0, 则在逐个导出时每个模型使用各自的当前动画时长")]
|
||||
public float Duration
|
||||
{
|
||||
get => duration;
|
||||
@@ -28,7 +28,7 @@ namespace SpineViewer.Exporter.Implementations.ExportArgs
|
||||
/// <summary>
|
||||
/// 帧率
|
||||
/// </summary>
|
||||
[Category("视频参数"), DisplayName("帧率"), Description("每秒画面数")]
|
||||
[Category("[1] 视频参数"), DisplayName("帧率"), Description("每秒画面数")]
|
||||
public float FPS { get; set; } = 60;
|
||||
|
||||
public override string? Validate()
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace SpineViewer.Exporter.Implementations.Exporter
|
||||
|
||||
// 独立导出时如果 args.Duration 小于 0 则使用自己的动画时长
|
||||
var duration = args.Duration;
|
||||
if (duration < 0) duration = spine.GetAnimationDuration(spine.CurrentAnimation);
|
||||
if (duration < 0) duration = spine.CurrentAnimationDuration;
|
||||
|
||||
float delta = 1f / args.FPS;
|
||||
int total = Math.Max(1, (int)(duration * args.FPS)); // 至少导出 1 帧
|
||||
|
||||
52
SpineViewer/MainForm.Designer.cs
generated
52
SpineViewer/MainForm.Designer.cs
generated
@@ -114,88 +114,88 @@
|
||||
//
|
||||
toolStripMenuItem_Open.Name = "toolStripMenuItem_Open";
|
||||
toolStripMenuItem_Open.ShortcutKeys = Keys.Control | Keys.O;
|
||||
toolStripMenuItem_Open.Size = new Size(270, 34);
|
||||
toolStripMenuItem_Open.Size = new Size(254, 34);
|
||||
toolStripMenuItem_Open.Text = "打开(&O)...";
|
||||
toolStripMenuItem_Open.Click += toolStripMenuItem_Open_Click;
|
||||
//
|
||||
// toolStripMenuItem_BatchOpen
|
||||
//
|
||||
toolStripMenuItem_BatchOpen.Name = "toolStripMenuItem_BatchOpen";
|
||||
toolStripMenuItem_BatchOpen.Size = new Size(270, 34);
|
||||
toolStripMenuItem_BatchOpen.Size = new Size(254, 34);
|
||||
toolStripMenuItem_BatchOpen.Text = "批量打开(&B)...";
|
||||
toolStripMenuItem_BatchOpen.Click += toolStripMenuItem_BatchOpen_Click;
|
||||
//
|
||||
// toolStripSeparator1
|
||||
//
|
||||
toolStripSeparator1.Name = "toolStripSeparator1";
|
||||
toolStripSeparator1.Size = new Size(267, 6);
|
||||
toolStripSeparator1.Size = new Size(251, 6);
|
||||
//
|
||||
// toolStripMenuItem_Export
|
||||
//
|
||||
toolStripMenuItem_Export.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_ExportFrame, toolStripMenuItem_ExportFrameSequence, toolStripMenuItem_ExportGif, toolStripMenuItem_ExportMkv, toolStripMenuItem_ExportMp4, toolStripMenuItem_ExportMov, toolStripMenuItem_ExportWebm });
|
||||
toolStripMenuItem_Export.Name = "toolStripMenuItem_Export";
|
||||
toolStripMenuItem_Export.Size = new Size(270, 34);
|
||||
toolStripMenuItem_Export.Size = new Size(254, 34);
|
||||
toolStripMenuItem_Export.Text = "导出(&E)";
|
||||
//
|
||||
// toolStripMenuItem_ExportFrame
|
||||
//
|
||||
toolStripMenuItem_ExportFrame.Name = "toolStripMenuItem_ExportFrame";
|
||||
toolStripMenuItem_ExportFrame.Size = new Size(270, 34);
|
||||
toolStripMenuItem_ExportFrame.Size = new Size(194, 34);
|
||||
toolStripMenuItem_ExportFrame.Text = "单帧画面...";
|
||||
toolStripMenuItem_ExportFrame.Click += toolStripMenuItem_Export_Click;
|
||||
//
|
||||
// toolStripMenuItem_ExportFrameSequence
|
||||
//
|
||||
toolStripMenuItem_ExportFrameSequence.Name = "toolStripMenuItem_ExportFrameSequence";
|
||||
toolStripMenuItem_ExportFrameSequence.Size = new Size(270, 34);
|
||||
toolStripMenuItem_ExportFrameSequence.Size = new Size(194, 34);
|
||||
toolStripMenuItem_ExportFrameSequence.Text = "帧序列...";
|
||||
toolStripMenuItem_ExportFrameSequence.Click += toolStripMenuItem_Export_Click;
|
||||
//
|
||||
// toolStripMenuItem_ExportGif
|
||||
//
|
||||
toolStripMenuItem_ExportGif.Name = "toolStripMenuItem_ExportGif";
|
||||
toolStripMenuItem_ExportGif.Size = new Size(270, 34);
|
||||
toolStripMenuItem_ExportGif.Size = new Size(194, 34);
|
||||
toolStripMenuItem_ExportGif.Text = "GIF...";
|
||||
toolStripMenuItem_ExportGif.Click += toolStripMenuItem_Export_Click;
|
||||
//
|
||||
// toolStripMenuItem_ExportMkv
|
||||
//
|
||||
toolStripMenuItem_ExportMkv.Name = "toolStripMenuItem_ExportMkv";
|
||||
toolStripMenuItem_ExportMkv.Size = new Size(270, 34);
|
||||
toolStripMenuItem_ExportMkv.Size = new Size(194, 34);
|
||||
toolStripMenuItem_ExportMkv.Text = "MKV";
|
||||
toolStripMenuItem_ExportMkv.Click += toolStripMenuItem_Export_Click;
|
||||
//
|
||||
// toolStripMenuItem_ExportMp4
|
||||
//
|
||||
toolStripMenuItem_ExportMp4.Name = "toolStripMenuItem_ExportMp4";
|
||||
toolStripMenuItem_ExportMp4.Size = new Size(270, 34);
|
||||
toolStripMenuItem_ExportMp4.Size = new Size(194, 34);
|
||||
toolStripMenuItem_ExportMp4.Text = "MP4...";
|
||||
toolStripMenuItem_ExportMp4.Click += toolStripMenuItem_Export_Click;
|
||||
//
|
||||
// toolStripMenuItem_ExportMov
|
||||
//
|
||||
toolStripMenuItem_ExportMov.Name = "toolStripMenuItem_ExportMov";
|
||||
toolStripMenuItem_ExportMov.Size = new Size(270, 34);
|
||||
toolStripMenuItem_ExportMov.Size = new Size(194, 34);
|
||||
toolStripMenuItem_ExportMov.Text = "MOV...";
|
||||
toolStripMenuItem_ExportMov.Click += toolStripMenuItem_Export_Click;
|
||||
//
|
||||
// toolStripMenuItem_ExportWebm
|
||||
//
|
||||
toolStripMenuItem_ExportWebm.Name = "toolStripMenuItem_ExportWebm";
|
||||
toolStripMenuItem_ExportWebm.Size = new Size(270, 34);
|
||||
toolStripMenuItem_ExportWebm.Size = new Size(194, 34);
|
||||
toolStripMenuItem_ExportWebm.Text = "WebM...";
|
||||
toolStripMenuItem_ExportWebm.Click += toolStripMenuItem_Export_Click;
|
||||
//
|
||||
// toolStripSeparator2
|
||||
//
|
||||
toolStripSeparator2.Name = "toolStripSeparator2";
|
||||
toolStripSeparator2.Size = new Size(267, 6);
|
||||
toolStripSeparator2.Size = new Size(251, 6);
|
||||
//
|
||||
// toolStripMenuItem_Exit
|
||||
//
|
||||
toolStripMenuItem_Exit.Name = "toolStripMenuItem_Exit";
|
||||
toolStripMenuItem_Exit.ShortcutKeys = Keys.Alt | Keys.F4;
|
||||
toolStripMenuItem_Exit.Size = new Size(270, 34);
|
||||
toolStripMenuItem_Exit.Size = new Size(254, 34);
|
||||
toolStripMenuItem_Exit.Text = "退出(&X)";
|
||||
toolStripMenuItem_Exit.Click += toolStripMenuItem_Exit_Click;
|
||||
//
|
||||
@@ -263,7 +263,7 @@
|
||||
rtbLog.Margin = new Padding(3, 2, 3, 2);
|
||||
rtbLog.Name = "rtbLog";
|
||||
rtbLog.ReadOnly = true;
|
||||
rtbLog.Size = new Size(1728, 114);
|
||||
rtbLog.Size = new Size(1728, 110);
|
||||
rtbLog.TabIndex = 0;
|
||||
rtbLog.Text = "";
|
||||
rtbLog.WordWrap = false;
|
||||
@@ -287,6 +287,7 @@
|
||||
splitContainer_MainForm.Panel2.Cursor = Cursors.Default;
|
||||
splitContainer_MainForm.Size = new Size(1728, 997);
|
||||
splitContainer_MainForm.SplitterDistance = 879;
|
||||
splitContainer_MainForm.SplitterWidth = 8;
|
||||
splitContainer_MainForm.TabIndex = 3;
|
||||
splitContainer_MainForm.TabStop = false;
|
||||
splitContainer_MainForm.SplitterMoved += splitContainer_SplitterMoved;
|
||||
@@ -310,6 +311,7 @@
|
||||
splitContainer_Functional.Panel2.Cursor = Cursors.Default;
|
||||
splitContainer_Functional.Size = new Size(1728, 879);
|
||||
splitContainer_Functional.SplitterDistance = 747;
|
||||
splitContainer_Functional.SplitterWidth = 8;
|
||||
splitContainer_Functional.TabIndex = 2;
|
||||
splitContainer_Functional.TabStop = false;
|
||||
splitContainer_Functional.SplitterMoved += splitContainer_SplitterMoved;
|
||||
@@ -333,6 +335,7 @@
|
||||
splitContainer_Information.Panel2.Cursor = Cursors.Default;
|
||||
splitContainer_Information.Size = new Size(747, 879);
|
||||
splitContainer_Information.SplitterDistance = 399;
|
||||
splitContainer_Information.SplitterWidth = 8;
|
||||
splitContainer_Information.TabIndex = 1;
|
||||
splitContainer_Information.TabStop = false;
|
||||
splitContainer_Information.SplitterMoved += splitContainer_SplitterMoved;
|
||||
@@ -364,7 +367,7 @@
|
||||
propertyGrid_Spine.HelpVisible = false;
|
||||
propertyGrid_Spine.Location = new Point(3, 26);
|
||||
propertyGrid_Spine.Name = "propertyGrid_Spine";
|
||||
propertyGrid_Spine.Size = new Size(338, 485);
|
||||
propertyGrid_Spine.Size = new Size(334, 509);
|
||||
propertyGrid_Spine.TabIndex = 0;
|
||||
propertyGrid_Spine.ToolbarVisible = false;
|
||||
propertyGrid_Spine.PropertyValueChanged += propertyGrid_PropertyValueChanged;
|
||||
@@ -379,15 +382,16 @@
|
||||
//
|
||||
// splitContainer_Config.Panel1
|
||||
//
|
||||
splitContainer_Config.Panel1.Controls.Add(groupBox_SkelConfig);
|
||||
splitContainer_Config.Panel1.Controls.Add(groupBox_PreviewConfig);
|
||||
splitContainer_Config.Panel1.Cursor = Cursors.Default;
|
||||
//
|
||||
// splitContainer_Config.Panel2
|
||||
//
|
||||
splitContainer_Config.Panel2.Controls.Add(groupBox_PreviewConfig);
|
||||
splitContainer_Config.Panel2.Controls.Add(groupBox_SkelConfig);
|
||||
splitContainer_Config.Panel2.Cursor = Cursors.Default;
|
||||
splitContainer_Config.Size = new Size(344, 879);
|
||||
splitContainer_Config.SplitterDistance = 514;
|
||||
splitContainer_Config.Size = new Size(340, 879);
|
||||
splitContainer_Config.SplitterDistance = 333;
|
||||
splitContainer_Config.SplitterWidth = 8;
|
||||
splitContainer_Config.TabIndex = 0;
|
||||
splitContainer_Config.TabStop = false;
|
||||
splitContainer_Config.SplitterMoved += splitContainer_SplitterMoved;
|
||||
@@ -399,7 +403,7 @@
|
||||
groupBox_SkelConfig.Dock = DockStyle.Fill;
|
||||
groupBox_SkelConfig.Location = new Point(0, 0);
|
||||
groupBox_SkelConfig.Name = "groupBox_SkelConfig";
|
||||
groupBox_SkelConfig.Size = new Size(344, 514);
|
||||
groupBox_SkelConfig.Size = new Size(340, 538);
|
||||
groupBox_SkelConfig.TabIndex = 0;
|
||||
groupBox_SkelConfig.TabStop = false;
|
||||
groupBox_SkelConfig.Text = "模型参数";
|
||||
@@ -410,7 +414,7 @@
|
||||
groupBox_PreviewConfig.Dock = DockStyle.Fill;
|
||||
groupBox_PreviewConfig.Location = new Point(0, 0);
|
||||
groupBox_PreviewConfig.Name = "groupBox_PreviewConfig";
|
||||
groupBox_PreviewConfig.Size = new Size(344, 361);
|
||||
groupBox_PreviewConfig.Size = new Size(340, 333);
|
||||
groupBox_PreviewConfig.TabIndex = 1;
|
||||
groupBox_PreviewConfig.TabStop = false;
|
||||
groupBox_PreviewConfig.Text = "画面参数";
|
||||
@@ -421,7 +425,7 @@
|
||||
propertyGrid_Previewer.HelpVisible = false;
|
||||
propertyGrid_Previewer.Location = new Point(3, 26);
|
||||
propertyGrid_Previewer.Name = "propertyGrid_Previewer";
|
||||
propertyGrid_Previewer.Size = new Size(338, 332);
|
||||
propertyGrid_Previewer.Size = new Size(334, 304);
|
||||
propertyGrid_Previewer.TabIndex = 1;
|
||||
propertyGrid_Previewer.ToolbarVisible = false;
|
||||
propertyGrid_Previewer.PropertyValueChanged += propertyGrid_PropertyValueChanged;
|
||||
@@ -432,7 +436,7 @@
|
||||
groupBox_Preview.Dock = DockStyle.Fill;
|
||||
groupBox_Preview.Location = new Point(0, 0);
|
||||
groupBox_Preview.Name = "groupBox_Preview";
|
||||
groupBox_Preview.Size = new Size(977, 879);
|
||||
groupBox_Preview.Size = new Size(973, 879);
|
||||
groupBox_Preview.TabIndex = 1;
|
||||
groupBox_Preview.TabStop = false;
|
||||
groupBox_Preview.Text = "预览画面";
|
||||
@@ -443,7 +447,7 @@
|
||||
spinePreviewer.Location = new Point(3, 26);
|
||||
spinePreviewer.Name = "spinePreviewer";
|
||||
spinePreviewer.PropertyGrid = propertyGrid_Previewer;
|
||||
spinePreviewer.Size = new Size(971, 850);
|
||||
spinePreviewer.Size = new Size(967, 850);
|
||||
spinePreviewer.SpineListView = spineListView;
|
||||
spinePreviewer.TabIndex = 0;
|
||||
//
|
||||
|
||||
@@ -87,15 +87,6 @@ namespace SpineViewer
|
||||
return;
|
||||
}
|
||||
|
||||
lock (spineListView.Spines)
|
||||
{
|
||||
if (spineListView.Spines.Count <= 0)
|
||||
{
|
||||
MessageBox.Info("请至少打开一个骨骼文件");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var exportArgs = ExportArgs.New(type, spinePreviewer.Resolution, spinePreviewer.GetView(), spinePreviewer.RenderSelectedOnly);
|
||||
var exportDialog = new Dialogs.ExportDialog() { ExportArgs = exportArgs };
|
||||
if (exportDialog.ShowDialog() != DialogResult.OK)
|
||||
@@ -156,7 +147,7 @@ namespace SpineViewer
|
||||
var worker = (BackgroundWorker)sender;
|
||||
var exporter = (Exporter.Exporter)e.Argument;
|
||||
spinePreviewer.StopRender();
|
||||
lock (spineListView.Spines) { exporter.Export(spineListView.Spines.ToArray(), (BackgroundWorker)sender); }
|
||||
lock (spineListView.Spines) { exporter.Export(spineListView.Spines.Where(sp => !sp.IsHidden).ToArray(), (BackgroundWorker)sender); }
|
||||
e.Cancel = worker.CancellationPending;
|
||||
spinePreviewer.StartRender();
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
texture.Repeated = true;
|
||||
|
||||
page.rendererObject = texture;
|
||||
page.width = (int)texture.Size.X;
|
||||
page.height = (int)texture.Size.Y;
|
||||
}
|
||||
|
||||
public void Unload(object texture)
|
||||
@@ -75,13 +73,19 @@ 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);
|
||||
CurrentAnimation = DefaultAnimationName;
|
||||
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -109,7 +113,8 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
var position = Position;
|
||||
var flipX = FlipX;
|
||||
var flipY = FlipY;
|
||||
var savedTrack0 = animationState.GetCurrent(0);
|
||||
var animation = CurrentAnimation;
|
||||
var skin = CurrentSkin;
|
||||
|
||||
var val = Math.Max(value, SCALE_MIN);
|
||||
if (skeletonBinary is not null)
|
||||
@@ -132,21 +137,8 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
Position = position;
|
||||
FlipX = flipX;
|
||||
FlipY = flipY;
|
||||
|
||||
// 恢复原本 Track0 上所有动画
|
||||
if (savedTrack0 is not null)
|
||||
{
|
||||
var entry = animationState.SetAnimation(0, savedTrack0.Animation.Name, true);
|
||||
entry.Time = savedTrack0.Time;
|
||||
// 2.1.x 没有提供 Next 访问器,故放弃还原后续动画,问题不大,因为预览画面目前不需要连续播放不同动画,只需要循环同一个动画
|
||||
//var savedEntry = savedTrack0.Next;
|
||||
//while (savedEntry is not null)
|
||||
//{
|
||||
// entry = animationState.AddAnimation(0, savedEntry.Animation.Name, true, 0);
|
||||
// entry.Time = savedEntry.TrackTime;
|
||||
// savedEntry = savedEntry.Next;
|
||||
//}
|
||||
}
|
||||
CurrentAnimation = animation;
|
||||
CurrentSkin = skin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,6 +177,18 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
@@ -333,7 +337,11 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
vertexArray.Clear();
|
||||
}
|
||||
states.BlendMode = blendMode;
|
||||
@@ -378,9 +386,12 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
//clipping.ClipEnd();
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 包围盒
|
||||
if (IsDebug && IsSelected && DebugBounds)
|
||||
{
|
||||
|
||||
@@ -26,8 +26,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
texture.Repeated = true;
|
||||
|
||||
page.rendererObject = texture;
|
||||
page.width = (int)texture.Size.X;
|
||||
page.height = (int)texture.Size.Y;
|
||||
}
|
||||
|
||||
public void Unload(object texture)
|
||||
@@ -74,13 +72,19 @@ 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);
|
||||
CurrentAnimation = DefaultAnimationName;
|
||||
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -108,7 +112,8 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
var position = Position;
|
||||
var flipX = FlipX;
|
||||
var flipY = FlipY;
|
||||
var savedTrack0 = animationState.GetCurrent(0);
|
||||
var animation = CurrentAnimation;
|
||||
var skin = CurrentSkin;
|
||||
|
||||
var val = Math.Max(value, SCALE_MIN);
|
||||
if (skeletonBinary is not null)
|
||||
@@ -131,20 +136,8 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
Position = position;
|
||||
FlipX = flipX;
|
||||
FlipY = flipY;
|
||||
|
||||
// 恢复原本 Track0 上所有动画
|
||||
if (savedTrack0 is not null)
|
||||
{
|
||||
var entry = animationState.SetAnimation(0, savedTrack0.Animation.Name, true);
|
||||
entry.TrackTime = savedTrack0.TrackTime;
|
||||
var savedEntry = savedTrack0.Next;
|
||||
while (savedEntry is not null)
|
||||
{
|
||||
entry = animationState.AddAnimation(0, savedEntry.Animation.Name, true, 0);
|
||||
entry.TrackTime = savedEntry.TrackTime;
|
||||
savedEntry = savedEntry.Next;
|
||||
}
|
||||
}
|
||||
CurrentAnimation = animation;
|
||||
CurrentSkin = skin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +176,18 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
@@ -289,7 +294,11 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
vertexArray.Clear();
|
||||
}
|
||||
states.BlendMode = blendMode;
|
||||
@@ -329,13 +338,16 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
clipping.ClipEnd(slot);
|
||||
}
|
||||
clipping.ClipEnd();
|
||||
|
||||
if (UsePremultipliedAlpha && (states.BlendMode == BlendModeSFML.Normal || states.BlendMode == BlendModeSFML.Additive))
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
clipping.ClipEnd();
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 包围盒
|
||||
if (IsDebug && IsSelected && DebugBounds)
|
||||
|
||||
@@ -23,8 +23,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
texture.Repeated = true;
|
||||
|
||||
page.rendererObject = texture;
|
||||
page.width = (int)texture.Size.X;
|
||||
page.height = (int)texture.Size.Y;
|
||||
}
|
||||
|
||||
public void Unload(object texture)
|
||||
@@ -72,6 +70,9 @@ 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);
|
||||
@@ -79,7 +80,9 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
foreach (var anime in skeletonData.Animations)
|
||||
animationNames.Add(anime.Name);
|
||||
|
||||
CurrentAnimation = DefaultAnimationName;
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -190,6 +193,18 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
@@ -297,7 +312,11 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
vertexArray.Clear();
|
||||
}
|
||||
states.BlendMode = blendMode;
|
||||
@@ -337,13 +356,16 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
clipping.ClipEnd(slot);
|
||||
}
|
||||
clipping.ClipEnd();
|
||||
|
||||
if (UsePremultipliedAlpha && (states.BlendMode == BlendModeSFML.Normal || states.BlendMode == BlendModeSFML.Additive))
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
clipping.ClipEnd();
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 包围盒
|
||||
if (IsDebug && IsSelected && DebugBounds)
|
||||
|
||||
@@ -26,8 +26,9 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
texture.Repeated = true;
|
||||
|
||||
page.rendererObject = texture;
|
||||
page.width = (int)texture.Size.X;
|
||||
page.height = (int)texture.Size.Y;
|
||||
// 似乎是不需要设置的, 因为存在某些 png 和 atlas 大小不同的情况, 一般是有一些缩放, 如果设置了反而渲染异常
|
||||
// page.width = (int)texture.Size.X;
|
||||
// page.height = (int)texture.Size.Y;
|
||||
}
|
||||
|
||||
public void Unload(object texture)
|
||||
@@ -75,6 +76,9 @@ 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);
|
||||
@@ -82,7 +86,9 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
foreach (var anime in skeletonData.Animations)
|
||||
animationNames.Add(anime.Name);
|
||||
|
||||
CurrentAnimation = DefaultAnimationName;
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -95,58 +101,11 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
public override float Scale
|
||||
{
|
||||
get
|
||||
{
|
||||
if (skeletonBinary is not null)
|
||||
return skeletonBinary.Scale;
|
||||
else if (skeletonJson is not null)
|
||||
return skeletonJson.Scale;
|
||||
else
|
||||
return 1f;
|
||||
}
|
||||
get => Math.Abs(skeleton.ScaleX);
|
||||
set
|
||||
{
|
||||
// 保存状态
|
||||
var position = Position;
|
||||
var flipX = FlipX;
|
||||
var flipY = FlipY;
|
||||
var savedTrack0 = animationState.GetCurrent(0);
|
||||
|
||||
var val = Math.Max(value, SCALE_MIN);
|
||||
if (skeletonBinary is not null)
|
||||
{
|
||||
skeletonBinary.Scale = val;
|
||||
skeletonData = skeletonBinary.ReadSkeletonData(SkelPath);
|
||||
}
|
||||
else if (skeletonJson is not null)
|
||||
{
|
||||
skeletonJson.Scale = val;
|
||||
skeletonData = skeletonJson.ReadSkeletonData(SkelPath);
|
||||
}
|
||||
|
||||
// reload skel-dependent data
|
||||
animationStateData = new AnimationStateData(skeletonData) { DefaultMix = animationStateData.DefaultMix };
|
||||
skeleton = new Skeleton(skeletonData);
|
||||
animationState = new AnimationState(animationStateData);
|
||||
|
||||
// 恢复状态
|
||||
Position = position;
|
||||
FlipX = flipX;
|
||||
FlipY = flipY;
|
||||
|
||||
// 恢复原本 Track0 上所有动画
|
||||
if (savedTrack0 is not null)
|
||||
{
|
||||
var entry = animationState.SetAnimation(0, savedTrack0.Animation.Name, true);
|
||||
entry.TrackTime = savedTrack0.TrackTime;
|
||||
var savedEntry = savedTrack0.Next;
|
||||
while (savedEntry is not null)
|
||||
{
|
||||
entry = animationState.AddAnimation(0, savedEntry.Animation.Name, true, 0);
|
||||
entry.TrackTime = savedEntry.TrackTime;
|
||||
savedEntry = savedEntry.Next;
|
||||
}
|
||||
}
|
||||
skeleton.ScaleX = Math.Sign(skeleton.ScaleX) * value;
|
||||
skeleton.ScaleY = Math.Sign(skeleton.ScaleY) * value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,6 +152,18 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
@@ -300,7 +271,11 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
vertexArray.Clear();
|
||||
}
|
||||
states.BlendMode = blendMode;
|
||||
@@ -340,15 +315,18 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
clipping.ClipEnd(slot);
|
||||
}
|
||||
clipping.ClipEnd();
|
||||
|
||||
if (UsePremultipliedAlpha && (states.BlendMode == BlendModeSFML.Normal || states.BlendMode == BlendModeSFML.Additive))
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
clipping.ClipEnd();
|
||||
|
||||
// 包围盒
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 调试包围盒
|
||||
if (IsDebug && IsSelected && DebugBounds)
|
||||
{
|
||||
var bounds = Bounds;
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
texture.Repeated = true;
|
||||
|
||||
page.rendererObject = texture;
|
||||
page.width = (int)texture.Size.X;
|
||||
page.height = (int)texture.Size.Y;
|
||||
}
|
||||
|
||||
public void Unload(object texture)
|
||||
@@ -74,6 +72,9 @@ 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);
|
||||
@@ -81,7 +82,9 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
foreach (var anime in skeletonData.Animations)
|
||||
animationNames.Add(anime.Name);
|
||||
|
||||
CurrentAnimation = DefaultAnimationName;
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -94,58 +97,11 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
public override float Scale
|
||||
{
|
||||
get
|
||||
{
|
||||
if (skeletonBinary is not null)
|
||||
return skeletonBinary.Scale;
|
||||
else if (skeletonJson is not null)
|
||||
return skeletonJson.Scale;
|
||||
else
|
||||
return 1f;
|
||||
}
|
||||
get => Math.Abs(skeleton.ScaleX);
|
||||
set
|
||||
{
|
||||
// 保存状态
|
||||
var position = Position;
|
||||
var flipX = FlipX;
|
||||
var flipY = FlipY;
|
||||
var savedTrack0 = animationState.GetCurrent(0);
|
||||
|
||||
var val = Math.Max(value, SCALE_MIN);
|
||||
if (skeletonBinary is not null)
|
||||
{
|
||||
skeletonBinary.Scale = val;
|
||||
skeletonData = skeletonBinary.ReadSkeletonData(SkelPath);
|
||||
}
|
||||
else if (skeletonJson is not null)
|
||||
{
|
||||
skeletonJson.Scale = val;
|
||||
skeletonData = skeletonJson.ReadSkeletonData(SkelPath);
|
||||
}
|
||||
|
||||
// reload skel-dependent data
|
||||
animationStateData = new AnimationStateData(skeletonData) { DefaultMix = animationStateData.DefaultMix };
|
||||
skeleton = new Skeleton(skeletonData);
|
||||
animationState = new AnimationState(animationStateData);
|
||||
|
||||
// 恢复状态
|
||||
Position = position;
|
||||
FlipX = flipX;
|
||||
FlipY = flipY;
|
||||
|
||||
// 恢复原本 Track0 上所有动画
|
||||
if (savedTrack0 is not null)
|
||||
{
|
||||
var entry = animationState.SetAnimation(0, savedTrack0.Animation.Name, true);
|
||||
entry.TrackTime = savedTrack0.TrackTime;
|
||||
var savedEntry = savedTrack0.Next;
|
||||
while (savedEntry is not null)
|
||||
{
|
||||
entry = animationState.AddAnimation(0, savedEntry.Animation.Name, true, 0);
|
||||
entry.TrackTime = savedEntry.TrackTime;
|
||||
savedEntry = savedEntry.Next;
|
||||
}
|
||||
}
|
||||
skeleton.ScaleX = Math.Sign(skeleton.ScaleX) * value;
|
||||
skeleton.ScaleY = Math.Sign(skeleton.ScaleY) * value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +148,18 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
@@ -299,7 +267,11 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
vertexArray.Clear();
|
||||
}
|
||||
states.BlendMode = blendMode;
|
||||
@@ -339,13 +311,16 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
clipping.ClipEnd(slot);
|
||||
}
|
||||
clipping.ClipEnd();
|
||||
|
||||
if (UsePremultipliedAlpha && (states.BlendMode == BlendModeSFML.Normal || states.BlendMode == BlendModeSFML.Additive))
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
clipping.ClipEnd();
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 包围盒
|
||||
if (IsDebug && IsSelected && DebugBounds)
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
texture.Repeated = true;
|
||||
|
||||
page.rendererObject = texture;
|
||||
page.width = (int)texture.Size.X;
|
||||
page.height = (int)texture.Size.Y;
|
||||
}
|
||||
|
||||
public void Unload(object texture)
|
||||
@@ -74,6 +72,9 @@ 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);
|
||||
@@ -81,7 +82,9 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
foreach (var anime in skeletonData.Animations)
|
||||
animationNames.Add(anime.Name);
|
||||
|
||||
CurrentAnimation = DefaultAnimationName;
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -94,58 +97,11 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
public override float Scale
|
||||
{
|
||||
get
|
||||
{
|
||||
if (skeletonBinary is not null)
|
||||
return skeletonBinary.Scale;
|
||||
else if (skeletonJson is not null)
|
||||
return skeletonJson.Scale;
|
||||
else
|
||||
return 1f;
|
||||
}
|
||||
get => Math.Abs(skeleton.ScaleX);
|
||||
set
|
||||
{
|
||||
// 保存状态
|
||||
var position = Position;
|
||||
var flipX = FlipX;
|
||||
var flipY = FlipY;
|
||||
var savedTrack0 = animationState.GetCurrent(0);
|
||||
|
||||
var val = Math.Max(value, SCALE_MIN);
|
||||
if (skeletonBinary is not null)
|
||||
{
|
||||
skeletonBinary.Scale = val;
|
||||
skeletonData = skeletonBinary.ReadSkeletonData(SkelPath);
|
||||
}
|
||||
else if (skeletonJson is not null)
|
||||
{
|
||||
skeletonJson.Scale = val;
|
||||
skeletonData = skeletonJson.ReadSkeletonData(SkelPath);
|
||||
}
|
||||
|
||||
// reload skel-dependent data
|
||||
animationStateData = new AnimationStateData(skeletonData) { DefaultMix = animationStateData.DefaultMix };
|
||||
skeleton = new Skeleton(skeletonData);
|
||||
animationState = new AnimationState(animationStateData);
|
||||
|
||||
// 恢复状态
|
||||
Position = position;
|
||||
FlipX = flipX;
|
||||
FlipY = flipY;
|
||||
|
||||
// 恢复原本 Track0 上所有动画
|
||||
if (savedTrack0 is not null)
|
||||
{
|
||||
var entry = animationState.SetAnimation(0, savedTrack0.Animation.Name, true);
|
||||
entry.TrackTime = savedTrack0.TrackTime;
|
||||
var savedEntry = savedTrack0.Next;
|
||||
while (savedEntry is not null)
|
||||
{
|
||||
entry = animationState.AddAnimation(0, savedEntry.Animation.Name, true, 0);
|
||||
entry.TrackTime = savedEntry.TrackTime;
|
||||
savedEntry = savedEntry.Next;
|
||||
}
|
||||
}
|
||||
skeleton.ScaleX = Math.Sign(skeleton.ScaleX) * value;
|
||||
skeleton.ScaleY = Math.Sign(skeleton.ScaleY) * value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +148,18 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
@@ -299,7 +267,11 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
vertexArray.Clear();
|
||||
}
|
||||
states.BlendMode = blendMode;
|
||||
@@ -339,13 +311,16 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
clipping.ClipEnd(slot);
|
||||
}
|
||||
clipping.ClipEnd();
|
||||
|
||||
if (UsePremultipliedAlpha && (states.BlendMode == BlendModeSFML.Normal || states.BlendMode == BlendModeSFML.Additive))
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
clipping.ClipEnd();
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 包围盒
|
||||
if (IsDebug && IsSelected && DebugBounds)
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
texture.Repeated = true;
|
||||
|
||||
page.rendererObject = texture;
|
||||
page.width = (int)texture.Size.X;
|
||||
page.height = (int)texture.Size.Y;
|
||||
}
|
||||
|
||||
public void Unload(object texture)
|
||||
@@ -74,6 +72,9 @@ 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);
|
||||
@@ -81,7 +82,9 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
foreach (var anime in skeletonData.Animations)
|
||||
animationNames.Add(anime.Name);
|
||||
|
||||
CurrentAnimation = DefaultAnimationName;
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -94,58 +97,11 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
public override float Scale
|
||||
{
|
||||
get
|
||||
{
|
||||
if (skeletonBinary is not null)
|
||||
return skeletonBinary.Scale;
|
||||
else if (skeletonJson is not null)
|
||||
return skeletonJson.Scale;
|
||||
else
|
||||
return 1f;
|
||||
}
|
||||
get => Math.Abs(skeleton.ScaleX);
|
||||
set
|
||||
{
|
||||
// 保存状态
|
||||
var position = Position;
|
||||
var flipX = FlipX;
|
||||
var flipY = FlipY;
|
||||
var savedTrack0 = animationState.GetCurrent(0);
|
||||
|
||||
var val = Math.Max(value, SCALE_MIN);
|
||||
if (skeletonBinary is not null)
|
||||
{
|
||||
skeletonBinary.Scale = val;
|
||||
skeletonData = skeletonBinary.ReadSkeletonData(SkelPath);
|
||||
}
|
||||
else if (skeletonJson is not null)
|
||||
{
|
||||
skeletonJson.Scale = val;
|
||||
skeletonData = skeletonJson.ReadSkeletonData(SkelPath);
|
||||
}
|
||||
|
||||
// reload skel-dependent data
|
||||
animationStateData = new AnimationStateData(skeletonData) { DefaultMix = animationStateData.DefaultMix };
|
||||
skeleton = new Skeleton(skeletonData);
|
||||
animationState = new AnimationState(animationStateData);
|
||||
|
||||
// 恢复状态
|
||||
Position = position;
|
||||
FlipX = flipX;
|
||||
FlipY = flipY;
|
||||
|
||||
// 恢复原本 Track0 上所有动画
|
||||
if (savedTrack0 is not null)
|
||||
{
|
||||
var entry = animationState.SetAnimation(0, savedTrack0.Animation.Name, true);
|
||||
entry.TrackTime = savedTrack0.TrackTime;
|
||||
var savedEntry = savedTrack0.Next;
|
||||
while (savedEntry is not null)
|
||||
{
|
||||
entry = animationState.AddAnimation(0, savedEntry.Animation.Name, true, 0);
|
||||
entry.TrackTime = savedEntry.TrackTime;
|
||||
savedEntry = savedEntry.Next;
|
||||
}
|
||||
}
|
||||
skeleton.ScaleX = Math.Sign(skeleton.ScaleX) * value;
|
||||
skeleton.ScaleY = Math.Sign(skeleton.ScaleY) * value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +148,18 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
@@ -299,7 +267,11 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
vertexArray.Clear();
|
||||
}
|
||||
states.BlendMode = blendMode;
|
||||
@@ -339,13 +311,16 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
clipping.ClipEnd(slot);
|
||||
}
|
||||
clipping.ClipEnd();
|
||||
|
||||
if (UsePremultipliedAlpha && (states.BlendMode == BlendModeSFML.Normal || states.BlendMode == BlendModeSFML.Additive))
|
||||
states.Shader = FragmentShader;
|
||||
else
|
||||
states.Shader = null;
|
||||
target.Draw(vertexArray, states);
|
||||
clipping.ClipEnd();
|
||||
|
||||
// 调试纹理
|
||||
if (!IsDebug || DebugTexture)
|
||||
target.Draw(vertexArray, states);
|
||||
|
||||
// 包围盒
|
||||
if (IsDebug && IsSelected && DebugBounds)
|
||||
|
||||
@@ -185,11 +185,6 @@ namespace SpineViewer.Spine
|
||||
return (Spine)Activator.CreateInstance(spineType, skelPath, atlasPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标识符
|
||||
/// </summary>
|
||||
public readonly string ID = Guid.NewGuid().ToString();
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
@@ -217,85 +212,93 @@ namespace SpineViewer.Spine
|
||||
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }
|
||||
protected virtual void Dispose(bool disposing) { preview?.Dispose(); }
|
||||
|
||||
#region 属性 | 基本信息
|
||||
#region 属性 | [0] 基本信息
|
||||
|
||||
/// <summary>
|
||||
/// 获取所属版本
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(VersionConverter))]
|
||||
[Category("基本信息"), DisplayName("运行时版本")]
|
||||
[Category("[0] 基本信息"), DisplayName("运行时版本")]
|
||||
public Version Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 资源所在完整目录
|
||||
/// </summary>
|
||||
[Category("基本信息"), DisplayName("资源目录")]
|
||||
[Category("[0] 基本信息"), DisplayName("资源目录")]
|
||||
public string AssetsDir { get; }
|
||||
|
||||
/// <summary>
|
||||
/// skel 文件完整路径
|
||||
/// </summary>
|
||||
[Category("基本信息"), DisplayName("skel文件路径")]
|
||||
[Category("[0] 基本信息"), DisplayName("skel文件路径")]
|
||||
public string SkelPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// atlas 文件完整路径
|
||||
/// </summary>
|
||||
[Category("基本信息"), DisplayName("atlas文件路径")]
|
||||
[Category("[0] 基本信息"), DisplayName("atlas文件路径")]
|
||||
public string AtlasPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
[Category("基本信息"), DisplayName("名称")]
|
||||
[Category("[0] 基本信息"), DisplayName("名称")]
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取所属文件版本
|
||||
/// </summary>
|
||||
[Category("基本信息"), DisplayName("文件版本")]
|
||||
[Category("[0] 基本信息"), DisplayName("文件版本")]
|
||||
public abstract string FileVersion { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region 属性 | 变换
|
||||
#region 属性 | [1] 设置
|
||||
|
||||
/// <summary>
|
||||
/// 是否被隐藏, 被隐藏的模型将仅仅在列表显示, 不参与其他行为
|
||||
/// </summary>
|
||||
[Category("[1] 设置"), DisplayName("是否隐藏")]
|
||||
public bool IsHidden { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用预乘Alpha
|
||||
/// </summary>
|
||||
[Category("[1] 设置"), DisplayName("预乘Alpha通道")]
|
||||
public bool UsePremultipliedAlpha { get; set; } = true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 属性 | [2] 变换
|
||||
|
||||
/// <summary>
|
||||
/// 缩放比例
|
||||
/// </summary>
|
||||
[Category("变换"), DisplayName("缩放比例")]
|
||||
[Category("[2] 变换"), DisplayName("缩放比例")]
|
||||
public abstract float Scale { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 位置
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(PointFConverter))]
|
||||
[Category("变换"), DisplayName("位置")]
|
||||
[Category("[2] 变换"), DisplayName("位置")]
|
||||
public abstract PointF Position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 水平翻转
|
||||
/// </summary>
|
||||
[Category("变换"), DisplayName("水平翻转")]
|
||||
[Category("[2] 变换"), DisplayName("水平翻转")]
|
||||
public abstract bool FlipX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 垂直翻转
|
||||
/// </summary>
|
||||
[Category("变换"), DisplayName("垂直翻转")]
|
||||
[Category("[2] 变换"), DisplayName("垂直翻转")]
|
||||
public abstract bool FlipY { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region 属性 | 画面
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用预乘Alpha
|
||||
/// </summary>
|
||||
[Category("画面"), DisplayName("预乘Alpha通道")]
|
||||
public bool UsePremultipliedAlpha { get; set; } = true;
|
||||
|
||||
#endregion
|
||||
#region 属性 | [3] 动画
|
||||
|
||||
/// <summary>
|
||||
/// 包含的所有动画名称
|
||||
@@ -304,29 +307,84 @@ namespace SpineViewer.Spine
|
||||
public ReadOnlyCollection<string> AnimationNames { get => animationNames.AsReadOnly(); }
|
||||
protected List<string> animationNames = [EMPTY_ANIMATION];
|
||||
|
||||
/// <summary>
|
||||
/// 默认动画名称
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public string DefaultAnimationName { get => animationNames.Last(); }
|
||||
|
||||
#region 属性 | 动画
|
||||
|
||||
/// <summary>
|
||||
/// 当前动画名称, 如果设置的动画不存在则忽略
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(AnimationConverter))]
|
||||
[Category("动画"), DisplayName("当前动画")]
|
||||
[Category("[3] 动画"), DisplayName("当前动画")]
|
||||
public abstract string CurrentAnimation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前动画时长
|
||||
/// </summary>
|
||||
[Category("动画"), DisplayName("当前动画时长")]
|
||||
[Category("[3] 动画"), DisplayName("当前动画时长")]
|
||||
public float CurrentAnimationDuration { get => GetAnimationDuration(CurrentAnimation); }
|
||||
|
||||
/// <summary>
|
||||
/// 包含的所有皮肤名称
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public ReadOnlyCollection<string> SkinNames { get => skinNames.AsReadOnly(); }
|
||||
protected List<string> skinNames = [];
|
||||
|
||||
/// <summary>
|
||||
/// 当前皮肤名称, 如果设置的皮肤不存在则忽略
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(SkinConverter))]
|
||||
[Category("[3] 动画"), DisplayName("当前皮肤")]
|
||||
public abstract string CurrentSkin { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region 属性 | [4] 调试
|
||||
|
||||
/// <summary>
|
||||
/// 显示调试
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public bool IsDebug { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 包围盒颜色
|
||||
/// </summary>
|
||||
protected static readonly SFML.Graphics.Color BoundsColor = new(120, 200, 0);
|
||||
|
||||
/// <summary>
|
||||
/// 包围盒顶点数组
|
||||
/// </summary>
|
||||
protected readonly SFML.Graphics.VertexArray boundsVertices = new(SFML.Graphics.PrimitiveType.LineStrip, 5);
|
||||
|
||||
/// <summary>
|
||||
/// 显示纹理
|
||||
/// </summary>
|
||||
[Category("[4] 调试"), DisplayName("显示纹理")]
|
||||
public bool DebugTexture { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 显示包围盒
|
||||
/// </summary>
|
||||
[Category("[4] 调试"), DisplayName("显示包围盒")]
|
||||
public bool DebugBounds { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 显示骨骼
|
||||
/// </summary>
|
||||
[Category("[4] 调试"), DisplayName("显示骨骼")]
|
||||
public bool DebugBones { get; set; } = false;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 标识符
|
||||
/// </summary>
|
||||
public readonly string ID = Guid.NewGuid().ToString();
|
||||
|
||||
/// <summary>
|
||||
/// 是否被选中
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public bool IsSelected { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 骨骼包围盒
|
||||
/// </summary>
|
||||
@@ -395,43 +453,8 @@ namespace SpineViewer.Spine
|
||||
/// <summary>
|
||||
/// 更新内部状态
|
||||
/// </summary>
|
||||
/// <param name="delta">时间间隔</param>
|
||||
public abstract void Update(float delta);
|
||||
|
||||
/// <summary>
|
||||
/// 是否被选中
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public bool IsSelected { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 显示调试
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public bool IsDebug { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 包围盒颜色
|
||||
/// </summary>
|
||||
protected static readonly SFML.Graphics.Color BoundsColor = new(120, 200, 0);
|
||||
|
||||
/// <summary>
|
||||
/// 包围盒顶点数组
|
||||
/// </summary>
|
||||
protected readonly SFML.Graphics.VertexArray boundsVertices = new(SFML.Graphics.PrimitiveType.LineStrip, 5);
|
||||
|
||||
/// <summary>
|
||||
/// 显示包围盒
|
||||
/// </summary>
|
||||
[Category("调试"), DisplayName("显示包围盒")]
|
||||
public bool DebugBounds { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 显示骨骼
|
||||
/// </summary>
|
||||
[Category("调试"), DisplayName("显示骨骼(TODO)")]
|
||||
public bool DebugBones { get; set; } = false;
|
||||
|
||||
#region SFML.Graphics.Drawable 接口实现
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -58,4 +58,38 @@ namespace SpineViewer.Spine
|
||||
return base.GetStandardValues(context);
|
||||
}
|
||||
}
|
||||
|
||||
public class SkinConverter : StringConverter
|
||||
{
|
||||
public override bool GetStandardValuesSupported(ITypeDescriptorContext? context)
|
||||
{
|
||||
// 支持标准值列表
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context)
|
||||
{
|
||||
// 排他模式,只有下拉列表中的值可选
|
||||
return true;
|
||||
}
|
||||
|
||||
public override StandardValuesCollection? GetStandardValues(ITypeDescriptorContext? context)
|
||||
{
|
||||
if (context?.Instance is Spine obj)
|
||||
{
|
||||
return new StandardValuesCollection(obj.SkinNames);
|
||||
}
|
||||
else if (context?.Instance is Spine[] spines)
|
||||
{
|
||||
if (spines.Length > 0)
|
||||
{
|
||||
IEnumerable<string> common = spines[0].SkinNames;
|
||||
foreach (var spine in spines.Skip(1))
|
||||
common = common.Intersect(spine.SkinNames);
|
||||
return new StandardValuesCollection(common.ToArray());
|
||||
}
|
||||
}
|
||||
return base.GetStandardValues(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<Version>0.11.1</Version>
|
||||
<Version>0.11.3</Version>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ApplicationIcon>appicon.ico</ApplicationIcon>
|
||||
|
||||
Reference in New Issue
Block a user