重构导出
This commit is contained in:
@@ -9,7 +9,6 @@ using System.Threading.Tasks;
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Security.Policy;
|
using System.Security.Policy;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using NLog.Targets;
|
|
||||||
|
|
||||||
namespace SpineViewer.Controls
|
namespace SpineViewer.Controls
|
||||||
{
|
{
|
||||||
@@ -246,6 +245,11 @@ namespace SpineViewer.Controls
|
|||||||
public uint MaxFps { get => maxFps; set { RenderWindow.SetFramerateLimit(value); maxFps = value; } }
|
public uint MaxFps { get => maxFps; set { RenderWindow.SetFramerateLimit(value); maxFps = value; } }
|
||||||
private uint maxFps = 60;
|
private uint maxFps = 60;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 View
|
||||||
|
/// </summary>
|
||||||
|
public SFML.Graphics.View GetView() => RenderWindow.GetView();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public SpinePreviewer()
|
public SpinePreviewer()
|
||||||
@@ -261,11 +265,6 @@ namespace SpineViewer.Controls
|
|||||||
MaxFps = 30;
|
MaxFps = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 预览画面帧参数, TODO: 转移到统一导出参数
|
|
||||||
/// </summary>
|
|
||||||
public SpinePreviewerFrameArgs GetFrameArgs() => new(Resolution, RenderWindow.GetView(), RenderSelectedOnly);
|
|
||||||
|
|
||||||
#region 渲染线程管理
|
#region 渲染线程管理
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -595,26 +594,4 @@ namespace SpineViewer.Controls
|
|||||||
PauseUpdate();
|
PauseUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 预览画面帧参数
|
|
||||||
/// </summary>
|
|
||||||
public class SpinePreviewerFrameArgs(Size resolution, SFML.Graphics.View view, bool renderSelectedOnly)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 分辨率
|
|
||||||
/// </summary>
|
|
||||||
public Size Resolution => resolution;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 渲染视窗
|
|
||||||
/// </summary>
|
|
||||||
public SFML.Graphics.View View => view;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否仅渲染/导出选中骨骼
|
|
||||||
/// </summary>
|
|
||||||
public bool RenderSelectedOnly => renderSelectedOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace SpineViewer.Dialogs
|
namespace SpineViewer.Dialogs
|
||||||
{
|
{
|
||||||
partial class ExportPreviewDialog
|
partial class ExportDialog
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
@@ -28,18 +28,13 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ExportPreviewDialog));
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ExportDialog));
|
||||||
panel1 = new Panel();
|
panel1 = new Panel();
|
||||||
tableLayoutPanel1 = new TableLayoutPanel();
|
tableLayoutPanel1 = new TableLayoutPanel();
|
||||||
propertyGrid = new PropertyGrid();
|
propertyGrid_ExportArgs = new PropertyGrid();
|
||||||
label4 = new Label();
|
|
||||||
label1 = new Label();
|
|
||||||
textBox_OutputDir = new TextBox();
|
|
||||||
button_SelectOutputDir = new Button();
|
|
||||||
tableLayoutPanel2 = new TableLayoutPanel();
|
tableLayoutPanel2 = new TableLayoutPanel();
|
||||||
button_Ok = new Button();
|
button_Ok = new Button();
|
||||||
button_Cancel = new Button();
|
button_Cancel = new Button();
|
||||||
folderBrowserDialog = new FolderBrowserDialog();
|
|
||||||
panel1.SuspendLayout();
|
panel1.SuspendLayout();
|
||||||
tableLayoutPanel1.SuspendLayout();
|
tableLayoutPanel1.SuspendLayout();
|
||||||
tableLayoutPanel2.SuspendLayout();
|
tableLayoutPanel2.SuspendLayout();
|
||||||
@@ -52,112 +47,58 @@
|
|||||||
panel1.Location = new Point(0, 0);
|
panel1.Location = new Point(0, 0);
|
||||||
panel1.Name = "panel1";
|
panel1.Name = "panel1";
|
||||||
panel1.Padding = new Padding(50, 15, 50, 10);
|
panel1.Padding = new Padding(50, 15, 50, 10);
|
||||||
panel1.Size = new Size(914, 482);
|
panel1.Size = new Size(710, 698);
|
||||||
panel1.TabIndex = 2;
|
panel1.TabIndex = 2;
|
||||||
//
|
//
|
||||||
// tableLayoutPanel1
|
// tableLayoutPanel1
|
||||||
//
|
//
|
||||||
tableLayoutPanel1.AutoSize = true;
|
tableLayoutPanel1.AutoSize = true;
|
||||||
tableLayoutPanel1.ColumnCount = 4;
|
tableLayoutPanel1.ColumnCount = 1;
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
tableLayoutPanel1.Controls.Add(propertyGrid_ExportArgs, 0, 0);
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 1);
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
|
||||||
tableLayoutPanel1.Controls.Add(propertyGrid, 0, 2);
|
|
||||||
tableLayoutPanel1.Controls.Add(label4, 0, 0);
|
|
||||||
tableLayoutPanel1.Controls.Add(label1, 0, 1);
|
|
||||||
tableLayoutPanel1.Controls.Add(textBox_OutputDir, 1, 1);
|
|
||||||
tableLayoutPanel1.Controls.Add(button_SelectOutputDir, 3, 1);
|
|
||||||
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 3);
|
|
||||||
tableLayoutPanel1.Dock = DockStyle.Fill;
|
tableLayoutPanel1.Dock = DockStyle.Fill;
|
||||||
tableLayoutPanel1.Location = new Point(50, 15);
|
tableLayoutPanel1.Location = new Point(50, 15);
|
||||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||||
tableLayoutPanel1.RowCount = 4;
|
tableLayoutPanel1.RowCount = 2;
|
||||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
|
||||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
|
||||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||||
tableLayoutPanel1.Size = new Size(814, 457);
|
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 20F));
|
||||||
|
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 20F));
|
||||||
|
tableLayoutPanel1.Size = new Size(610, 673);
|
||||||
tableLayoutPanel1.TabIndex = 0;
|
tableLayoutPanel1.TabIndex = 0;
|
||||||
//
|
//
|
||||||
// propertyGrid
|
// propertyGrid_ExportArgs
|
||||||
//
|
//
|
||||||
tableLayoutPanel1.SetColumnSpan(propertyGrid, 4);
|
propertyGrid_ExportArgs.Dock = DockStyle.Fill;
|
||||||
propertyGrid.Dock = DockStyle.Fill;
|
propertyGrid_ExportArgs.Location = new Point(3, 3);
|
||||||
propertyGrid.HelpVisible = false;
|
propertyGrid_ExportArgs.Name = "propertyGrid_ExportArgs";
|
||||||
propertyGrid.Location = new Point(3, 97);
|
propertyGrid_ExportArgs.Size = new Size(604, 594);
|
||||||
propertyGrid.Name = "propertyGrid";
|
propertyGrid_ExportArgs.TabIndex = 1;
|
||||||
propertyGrid.Size = new Size(808, 284);
|
propertyGrid_ExportArgs.ToolbarVisible = false;
|
||||||
propertyGrid.TabIndex = 1;
|
|
||||||
propertyGrid.ToolbarVisible = false;
|
|
||||||
//
|
|
||||||
// label4
|
|
||||||
//
|
|
||||||
label4.AutoSize = true;
|
|
||||||
tableLayoutPanel1.SetColumnSpan(label4, 4);
|
|
||||||
label4.Dock = DockStyle.Fill;
|
|
||||||
label4.Location = new Point(15, 15);
|
|
||||||
label4.Margin = new Padding(15);
|
|
||||||
label4.Name = "label4";
|
|
||||||
label4.Size = new Size(784, 24);
|
|
||||||
label4.TabIndex = 11;
|
|
||||||
label4.Text = "说明:输出文件夹为可选项,留空则将预览图输出到每个骨骼文件所在目录";
|
|
||||||
label4.TextAlign = ContentAlignment.MiddleCenter;
|
|
||||||
//
|
|
||||||
// label1
|
|
||||||
//
|
|
||||||
label1.Anchor = AnchorStyles.Right;
|
|
||||||
label1.AutoSize = true;
|
|
||||||
label1.Location = new Point(3, 62);
|
|
||||||
label1.Name = "label1";
|
|
||||||
label1.Size = new Size(104, 24);
|
|
||||||
label1.TabIndex = 0;
|
|
||||||
label1.Text = "输出文件夹:";
|
|
||||||
//
|
|
||||||
// textBox_OutputDir
|
|
||||||
//
|
|
||||||
tableLayoutPanel1.SetColumnSpan(textBox_OutputDir, 2);
|
|
||||||
textBox_OutputDir.Dock = DockStyle.Fill;
|
|
||||||
textBox_OutputDir.Location = new Point(113, 57);
|
|
||||||
textBox_OutputDir.Name = "textBox_OutputDir";
|
|
||||||
textBox_OutputDir.Size = new Size(660, 30);
|
|
||||||
textBox_OutputDir.TabIndex = 3;
|
|
||||||
//
|
|
||||||
// button_SelectOutputDir
|
|
||||||
//
|
|
||||||
button_SelectOutputDir.AutoSize = true;
|
|
||||||
button_SelectOutputDir.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
|
||||||
button_SelectOutputDir.Location = new Point(779, 57);
|
|
||||||
button_SelectOutputDir.Name = "button_SelectOutputDir";
|
|
||||||
button_SelectOutputDir.Size = new Size(32, 34);
|
|
||||||
button_SelectOutputDir.TabIndex = 5;
|
|
||||||
button_SelectOutputDir.Text = "...";
|
|
||||||
button_SelectOutputDir.UseVisualStyleBackColor = true;
|
|
||||||
button_SelectOutputDir.Click += button_SelectOutputDir_Click;
|
|
||||||
//
|
//
|
||||||
// tableLayoutPanel2
|
// tableLayoutPanel2
|
||||||
//
|
//
|
||||||
tableLayoutPanel2.AutoSize = true;
|
tableLayoutPanel2.AutoSize = true;
|
||||||
tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
tableLayoutPanel2.ColumnCount = 2;
|
tableLayoutPanel2.ColumnCount = 2;
|
||||||
tableLayoutPanel1.SetColumnSpan(tableLayoutPanel2, 4);
|
|
||||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||||
tableLayoutPanel2.Controls.Add(button_Ok, 0, 0);
|
tableLayoutPanel2.Controls.Add(button_Ok, 0, 0);
|
||||||
tableLayoutPanel2.Controls.Add(button_Cancel, 1, 0);
|
tableLayoutPanel2.Controls.Add(button_Cancel, 1, 0);
|
||||||
tableLayoutPanel2.Dock = DockStyle.Bottom;
|
tableLayoutPanel2.Dock = DockStyle.Bottom;
|
||||||
tableLayoutPanel2.Location = new Point(3, 414);
|
tableLayoutPanel2.Location = new Point(3, 630);
|
||||||
tableLayoutPanel2.Margin = new Padding(3, 30, 3, 3);
|
tableLayoutPanel2.Margin = new Padding(3, 30, 3, 3);
|
||||||
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||||
tableLayoutPanel2.RowCount = 1;
|
tableLayoutPanel2.RowCount = 1;
|
||||||
tableLayoutPanel2.RowStyles.Add(new RowStyle());
|
tableLayoutPanel2.RowStyles.Add(new RowStyle());
|
||||||
tableLayoutPanel2.Size = new Size(808, 40);
|
tableLayoutPanel2.Size = new Size(604, 40);
|
||||||
tableLayoutPanel2.TabIndex = 10;
|
tableLayoutPanel2.TabIndex = 10;
|
||||||
//
|
//
|
||||||
// button_Ok
|
// button_Ok
|
||||||
//
|
//
|
||||||
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||||
button_Ok.Location = new Point(262, 3);
|
button_Ok.Location = new Point(160, 3);
|
||||||
button_Ok.Margin = new Padding(3, 3, 30, 3);
|
button_Ok.Margin = new Padding(3, 3, 30, 3);
|
||||||
button_Ok.Name = "button_Ok";
|
button_Ok.Name = "button_Ok";
|
||||||
button_Ok.Size = new Size(112, 34);
|
button_Ok.Size = new Size(112, 34);
|
||||||
@@ -169,7 +110,7 @@
|
|||||||
// button_Cancel
|
// button_Cancel
|
||||||
//
|
//
|
||||||
button_Cancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
|
button_Cancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
|
||||||
button_Cancel.Location = new Point(434, 3);
|
button_Cancel.Location = new Point(332, 3);
|
||||||
button_Cancel.Margin = new Padding(30, 3, 3, 3);
|
button_Cancel.Margin = new Padding(30, 3, 3, 3);
|
||||||
button_Cancel.Name = "button_Cancel";
|
button_Cancel.Name = "button_Cancel";
|
||||||
button_Cancel.Size = new Size(112, 34);
|
button_Cancel.Size = new Size(112, 34);
|
||||||
@@ -178,26 +119,22 @@
|
|||||||
button_Cancel.UseVisualStyleBackColor = true;
|
button_Cancel.UseVisualStyleBackColor = true;
|
||||||
button_Cancel.Click += button_Cancel_Click;
|
button_Cancel.Click += button_Cancel_Click;
|
||||||
//
|
//
|
||||||
// folderBrowserDialog
|
// ExportDialog
|
||||||
//
|
|
||||||
folderBrowserDialog.AddToRecent = false;
|
|
||||||
//
|
|
||||||
// ExportPreviewDialog
|
|
||||||
//
|
//
|
||||||
AcceptButton = button_Ok;
|
AcceptButton = button_Ok;
|
||||||
AutoScaleDimensions = new SizeF(11F, 24F);
|
AutoScaleDimensions = new SizeF(11F, 24F);
|
||||||
AutoScaleMode = AutoScaleMode.Font;
|
AutoScaleMode = AutoScaleMode.Font;
|
||||||
CancelButton = button_Cancel;
|
CancelButton = button_Cancel;
|
||||||
ClientSize = new Size(914, 482);
|
ClientSize = new Size(710, 698);
|
||||||
Controls.Add(panel1);
|
Controls.Add(panel1);
|
||||||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||||
MaximizeBox = false;
|
MaximizeBox = false;
|
||||||
MinimizeBox = false;
|
MinimizeBox = false;
|
||||||
Name = "ExportPreviewDialog";
|
Name = "ExportDialog";
|
||||||
ShowInTaskbar = false;
|
ShowInTaskbar = false;
|
||||||
StartPosition = FormStartPosition.CenterScreen;
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
Text = "导出预览图";
|
Text = "导出参数";
|
||||||
panel1.ResumeLayout(false);
|
panel1.ResumeLayout(false);
|
||||||
panel1.PerformLayout();
|
panel1.PerformLayout();
|
||||||
tableLayoutPanel1.ResumeLayout(false);
|
tableLayoutPanel1.ResumeLayout(false);
|
||||||
@@ -210,14 +147,9 @@
|
|||||||
|
|
||||||
private Panel panel1;
|
private Panel panel1;
|
||||||
private TableLayoutPanel tableLayoutPanel1;
|
private TableLayoutPanel tableLayoutPanel1;
|
||||||
private Label label4;
|
|
||||||
private Label label1;
|
|
||||||
private TextBox textBox_OutputDir;
|
|
||||||
private Button button_SelectOutputDir;
|
|
||||||
private TableLayoutPanel tableLayoutPanel2;
|
private TableLayoutPanel tableLayoutPanel2;
|
||||||
private Button button_Ok;
|
private Button button_Ok;
|
||||||
private Button button_Cancel;
|
private Button button_Cancel;
|
||||||
private FolderBrowserDialog folderBrowserDialog;
|
private PropertyGrid propertyGrid_ExportArgs;
|
||||||
private PropertyGrid propertyGrid;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
47
SpineViewer/Dialogs/ExportDialog.cs
Normal file
47
SpineViewer/Dialogs/ExportDialog.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using SpineViewer.ExportHelper;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Design;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace SpineViewer.Dialogs
|
||||||
|
{
|
||||||
|
public partial class ExportDialog: Form
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 要绑定的导出参数
|
||||||
|
/// </summary>
|
||||||
|
public required ExportArgs ExportArgs
|
||||||
|
{
|
||||||
|
get => propertyGrid_ExportArgs.SelectedObject as ExportArgs;
|
||||||
|
init => propertyGrid_ExportArgs.SelectedObject = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportDialog()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button_Ok_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (ExportArgs.Validate() is string error)
|
||||||
|
{
|
||||||
|
MessageBox.Info(error, "参数错误");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button_Cancel_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -117,9 +117,6 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<metadata name="folderBrowserDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
|
||||||
<value>17, 17</value>
|
|
||||||
</metadata>
|
|
||||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Data;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Drawing.Imaging;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace SpineViewer.Dialogs
|
|
||||||
{
|
|
||||||
public partial class ExportPreviewDialog: Form
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 对话框结果
|
|
||||||
/// </summary>
|
|
||||||
public readonly ExportPreviewDialogResult Result = new();
|
|
||||||
|
|
||||||
public ExportPreviewDialog()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
propertyGrid.SelectedObject = Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void button_SelectOutputDir_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
folderBrowserDialog.InitialDirectory = textBox_OutputDir.Text;
|
|
||||||
if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
|
|
||||||
return;
|
|
||||||
textBox_OutputDir.Text = Path.GetFullPath(folderBrowserDialog.SelectedPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void button_Ok_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
var outputDir = textBox_OutputDir.Text;
|
|
||||||
if (string.IsNullOrEmpty(outputDir))
|
|
||||||
{
|
|
||||||
outputDir = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (File.Exists(outputDir))
|
|
||||||
{
|
|
||||||
MessageBox.Info("输出文件夹无效");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Directory.Exists(outputDir))
|
|
||||||
{
|
|
||||||
if (MessageBox.Quest($"文件夹 {outputDir} 不存在,是否创建?") != DialogResult.OK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(outputDir);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Program.Logger.Error(ex.ToString());
|
|
||||||
MessageBox.Error(ex.ToString(), "文件夹创建失败");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outputDir = Path.GetFullPath(outputDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputDir is null && string.IsNullOrEmpty(Result.NameSuffix))
|
|
||||||
{
|
|
||||||
MessageBox.Info("输出文件夹和名称后缀不可同时为空,存在文件覆盖风险");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result.OutputDir = outputDir;
|
|
||||||
DialogResult = DialogResult.OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void button_Cancel_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
DialogResult = DialogResult.Cancel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ExportPreviewDialogResult
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 输出路径
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
public string? OutputDir { get; set; } = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 预览图格式
|
|
||||||
/// </summary>
|
|
||||||
[TypeConverter(typeof(ImageFormatConverter))]
|
|
||||||
[Category("图像"), DisplayName("预览图格式")]
|
|
||||||
public ImageFormat ImageFormat
|
|
||||||
{
|
|
||||||
get => imageFormat;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == ImageFormat.MemoryBmp) value = ImageFormat.Bmp;
|
|
||||||
imageFormat = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private ImageFormat imageFormat = ImageFormat.Png;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 预览图分辨率
|
|
||||||
/// </summary>
|
|
||||||
[TypeConverter(typeof(SizeConverter))]
|
|
||||||
[Category("图像"), DisplayName("分辨率")]
|
|
||||||
public Size Resolution
|
|
||||||
{
|
|
||||||
get => resolution;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value.Width <= 0) value.Width = 128;
|
|
||||||
if (value.Height <= 0) value.Height = 128;
|
|
||||||
resolution = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private Size resolution = new(512, 512);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 四周填充像素值
|
|
||||||
/// </summary>
|
|
||||||
[TypeConverter(typeof(PaddingConverter))]
|
|
||||||
[Category("图像"), DisplayName("四周填充像素值")]
|
|
||||||
public Padding Padding
|
|
||||||
{
|
|
||||||
get => padding;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value.Left <= 0) value.Left = 10;
|
|
||||||
if (value.Right <= 0) value.Right = 10;
|
|
||||||
if (value.Top <= 0) value.Top = 10;
|
|
||||||
if (value.Bottom <= 0) value.Bottom = 10;
|
|
||||||
padding = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private Padding padding = new(1);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// DPI
|
|
||||||
/// </summary>
|
|
||||||
[TypeConverter(typeof(SizeFConverter))]
|
|
||||||
[Category("图像"), DisplayName("DPI")]
|
|
||||||
public SizeF DPI
|
|
||||||
{
|
|
||||||
get => dpi;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value.Width <= 0) value.Width = 144;
|
|
||||||
if (value.Height <= 0) value.Height = 144;
|
|
||||||
dpi = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private SizeF dpi = new(144, 144);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 名称后缀
|
|
||||||
/// </summary>
|
|
||||||
[Category("其他"), DisplayName("名称后缀")]
|
|
||||||
public string NameSuffix { get; set; } = "(preview)";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
153
SpineViewer/ExportHelper/ExportArgs.cs
Normal file
153
SpineViewer/ExportHelper/ExportArgs.cs
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing.Design;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SpineViewer.ExportHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 导出参数基类
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ExportArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 输出文件夹
|
||||||
|
/// </summary>
|
||||||
|
[Editor(typeof(FolderNameEditor), typeof(UITypeEditor))]
|
||||||
|
[Category("导出"), DisplayName("输出文件夹"), Description("逐个导出时可以留空,将逐个导出到模型自身所在目录")]
|
||||||
|
public string? OutputDir { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 逐个导出
|
||||||
|
/// </summary>
|
||||||
|
[Category("导出"), DisplayName("导出单个"), Description("是否将模型在同一个画面上导出单个文件,否则逐个导出模型")]
|
||||||
|
public bool ExportSingle { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画面分辨率
|
||||||
|
/// </summary>
|
||||||
|
[TypeConverter(typeof(SizeConverter))]
|
||||||
|
[Category("导出"), DisplayName("分辨率"), Description("画面的宽高像素大小")]
|
||||||
|
public required Size Resolution { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 渲染视窗
|
||||||
|
/// </summary>
|
||||||
|
[Browsable(false)]
|
||||||
|
public required SFML.Graphics.View View { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否仅渲染选中
|
||||||
|
/// </summary>
|
||||||
|
[Category("导出"), DisplayName("仅渲染选中"), Description("是否仅导出选中的模型")]
|
||||||
|
public required bool RenderSelectedOnly { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查参数是否合法并规范化参数值, 否则返回用户错误原因
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual string? Validate()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(OutputDir) && File.Exists(OutputDir))
|
||||||
|
return "输出文件夹无效";
|
||||||
|
if (!string.IsNullOrEmpty(OutputDir) && !Directory.Exists(OutputDir))
|
||||||
|
return $"文件夹 {OutputDir} 不存在";
|
||||||
|
if (ExportSingle && string.IsNullOrEmpty(OutputDir))
|
||||||
|
return "导出单个时必须提供输出文件夹";
|
||||||
|
|
||||||
|
OutputDir = string.IsNullOrEmpty(OutputDir) ? null : Path.GetFullPath(OutputDir);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画面帧导出参数
|
||||||
|
/// </summary>
|
||||||
|
public class ExportFrameArgs : ExportArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 名称后缀
|
||||||
|
/// </summary>
|
||||||
|
[Category("画面帧"), DisplayName("名称后缀"), Description("逐个导出时必须提供该值,否则存在文件覆盖风险")]
|
||||||
|
public string NameSuffix { get; set; } = "(preview)";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画面帧格式
|
||||||
|
/// </summary>
|
||||||
|
[TypeConverter(typeof(ImageFormatConverter))]
|
||||||
|
[Category("画面帧"), DisplayName("图像格式")]
|
||||||
|
public ImageFormat ImageFormat
|
||||||
|
{
|
||||||
|
get => imageFormat;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == ImageFormat.MemoryBmp) value = ImageFormat.Bmp;
|
||||||
|
imageFormat = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private ImageFormat imageFormat = ImageFormat.Png;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 文件名后缀
|
||||||
|
/// </summary>
|
||||||
|
[Category("画面帧"), DisplayName("文件名后缀"), Description("与图像格式匹配的文件名后缀")]
|
||||||
|
public string FileSuffix { get => imageFormat.GetSuffix(); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 四周填充像素值
|
||||||
|
/// </summary>
|
||||||
|
[TypeConverter(typeof(PaddingConverter))]
|
||||||
|
[Category("画面帧"), DisplayName("四周填充像素值"), Description("在图内四周留出来的透明像素区域, 画面内容的可用范围是分辨率裁去填充区域")]
|
||||||
|
public Padding Padding
|
||||||
|
{
|
||||||
|
get => padding;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value.Left < 0) value.Left = 0;
|
||||||
|
if (value.Right < 0) value.Right = 0;
|
||||||
|
if (value.Top < 0) value.Top = 0;
|
||||||
|
if (value.Bottom < 0) value.Bottom = 0;
|
||||||
|
padding = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Padding padding = new(1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DPI
|
||||||
|
/// </summary>
|
||||||
|
[TypeConverter(typeof(SizeFConverter))]
|
||||||
|
[Category("画面帧"), DisplayName("DPI"), Description("导出图像的每英寸像素数,用于调整图像的物理尺寸")]
|
||||||
|
public SizeF DPI
|
||||||
|
{
|
||||||
|
get => dpi;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value.Width <= 0) value.Width = 144;
|
||||||
|
if (value.Height <= 0) value.Height = 144;
|
||||||
|
dpi = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private SizeF dpi = new(144, 144);
|
||||||
|
|
||||||
|
public override string? Validate()
|
||||||
|
{
|
||||||
|
if (base.Validate() is string error)
|
||||||
|
return error;
|
||||||
|
if (string.IsNullOrEmpty(OutputDir) && string.IsNullOrEmpty(NameSuffix))
|
||||||
|
return "输出文件夹和名称后缀不可同时为空,存在文件覆盖风险";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 视频导出参数基类
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ExportVideoArgs:ExportArgs
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,5 +38,47 @@ namespace SpineViewer.ExportHelper
|
|||||||
else if (imageFormat == ImageFormat.Exif) return ".jpg";
|
else if (imageFormat == ImageFormat.Exif) return ".jpg";
|
||||||
else return $".{imageFormat.ToString().ToLower()}";
|
else return $".{imageFormat.ToString().ToLower()}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取某个包围盒下合适的视图
|
||||||
|
/// </summary>
|
||||||
|
public static SFML.Graphics.View GetView(this RectangleF bounds, Size resolution, Padding padding)
|
||||||
|
=> GetView(bounds, (uint)resolution.Width, (uint)resolution.Height, (uint)padding.Left, (uint)padding.Right, (uint)padding.Top, (uint)padding.Bottom);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取某个包围盒下合适的视图
|
||||||
|
/// </summary>
|
||||||
|
public static SFML.Graphics.View GetView(this RectangleF bounds, uint width, uint height, Padding padding)
|
||||||
|
=> GetView(bounds, width, height, (uint)padding.Left, (uint)padding.Right, (uint)padding.Top, (uint)padding.Bottom);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取某个包围盒下合适的视图
|
||||||
|
/// </summary>
|
||||||
|
public static SFML.Graphics.View GetView(this RectangleF bounds, Size resolution, uint paddingL = 1, uint paddingR = 1, uint paddingT = 1, uint paddingB = 1)
|
||||||
|
=> GetView(bounds, (uint)resolution.Width, (uint)resolution.Height, paddingL, paddingR, paddingT, paddingB);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取某个包围盒下合适的视图
|
||||||
|
/// </summary>
|
||||||
|
public static SFML.Graphics.View GetView(this RectangleF bounds, uint width, uint height, uint paddingL = 1, uint paddingR = 1, uint paddingT = 1, uint paddingB = 1)
|
||||||
|
{
|
||||||
|
float sizeX = bounds.Width;
|
||||||
|
float sizeY = bounds.Height;
|
||||||
|
float innerW = width - paddingL - paddingR;
|
||||||
|
float innerH = height - paddingT - paddingB;
|
||||||
|
|
||||||
|
float scale = 1;
|
||||||
|
if ((sizeY / sizeX) < (innerH / innerW))
|
||||||
|
scale = sizeX / innerW; // 相同的 X, 视窗 Y 更大
|
||||||
|
else
|
||||||
|
scale = sizeY / innerH; // 相同的 Y, 视窗 X 更大
|
||||||
|
|
||||||
|
var x = bounds.X + bounds.Width / 2 + ((float)paddingL - (float)paddingR) * scale;
|
||||||
|
var y = bounds.Y + bounds.Height / 2 + ((float)paddingT - (float)paddingB) * scale;
|
||||||
|
var viewX = width * scale;
|
||||||
|
var viewY = height * scale;
|
||||||
|
|
||||||
|
return new(new(x, y), new(viewX, -viewY));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
86
SpineViewer/MainForm.Designer.cs
generated
86
SpineViewer/MainForm.Designer.cs
generated
@@ -36,7 +36,13 @@
|
|||||||
toolStripMenuItem_BatchOpen = new ToolStripMenuItem();
|
toolStripMenuItem_BatchOpen = new ToolStripMenuItem();
|
||||||
toolStripSeparator1 = new ToolStripSeparator();
|
toolStripSeparator1 = new ToolStripSeparator();
|
||||||
toolStripMenuItem_Export = new ToolStripMenuItem();
|
toolStripMenuItem_Export = new ToolStripMenuItem();
|
||||||
toolStripMenuItem_ExportPreview = new ToolStripMenuItem();
|
toolStripMenuItem_ExportFrame = new ToolStripMenuItem();
|
||||||
|
toolStripMenuItem_ExportFrames = new ToolStripMenuItem();
|
||||||
|
toolStripMenuItem_ExportGif = new ToolStripMenuItem();
|
||||||
|
toolStripMenuItem_ExportMkv = new ToolStripMenuItem();
|
||||||
|
toolStripMenuItem_ExportMp4 = new ToolStripMenuItem();
|
||||||
|
toolStripMenuItem_ExportMov = new ToolStripMenuItem();
|
||||||
|
toolStripMenuItem_ExportWebm = new ToolStripMenuItem();
|
||||||
toolStripSeparator2 = new ToolStripSeparator();
|
toolStripSeparator2 = new ToolStripSeparator();
|
||||||
toolStripMenuItem_Exit = new ToolStripMenuItem();
|
toolStripMenuItem_Exit = new ToolStripMenuItem();
|
||||||
toolStripMenuItem_Tool = new ToolStripMenuItem();
|
toolStripMenuItem_Tool = new ToolStripMenuItem();
|
||||||
@@ -99,7 +105,7 @@
|
|||||||
//
|
//
|
||||||
// toolStripMenuItem_File
|
// toolStripMenuItem_File
|
||||||
//
|
//
|
||||||
toolStripMenuItem_File.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_Open, toolStripMenuItem_BatchOpen, toolStripSeparator1, toolStripMenuItem_Export, toolStripMenuItem_ExportPreview, toolStripSeparator2, toolStripMenuItem_Exit });
|
toolStripMenuItem_File.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_Open, toolStripMenuItem_BatchOpen, toolStripSeparator1, toolStripMenuItem_Export, toolStripSeparator2, toolStripMenuItem_Exit });
|
||||||
toolStripMenuItem_File.Name = "toolStripMenuItem_File";
|
toolStripMenuItem_File.Name = "toolStripMenuItem_File";
|
||||||
toolStripMenuItem_File.Size = new Size(84, 28);
|
toolStripMenuItem_File.Size = new Size(84, 28);
|
||||||
toolStripMenuItem_File.Text = "文件(&F)";
|
toolStripMenuItem_File.Text = "文件(&F)";
|
||||||
@@ -108,47 +114,83 @@
|
|||||||
//
|
//
|
||||||
toolStripMenuItem_Open.Name = "toolStripMenuItem_Open";
|
toolStripMenuItem_Open.Name = "toolStripMenuItem_Open";
|
||||||
toolStripMenuItem_Open.ShortcutKeys = Keys.Control | Keys.O;
|
toolStripMenuItem_Open.ShortcutKeys = Keys.Control | Keys.O;
|
||||||
toolStripMenuItem_Open.Size = new Size(254, 34);
|
toolStripMenuItem_Open.Size = new Size(270, 34);
|
||||||
toolStripMenuItem_Open.Text = "打开(&O)...";
|
toolStripMenuItem_Open.Text = "打开(&O)...";
|
||||||
toolStripMenuItem_Open.Click += toolStripMenuItem_Open_Click;
|
toolStripMenuItem_Open.Click += toolStripMenuItem_Open_Click;
|
||||||
//
|
//
|
||||||
// toolStripMenuItem_BatchOpen
|
// toolStripMenuItem_BatchOpen
|
||||||
//
|
//
|
||||||
toolStripMenuItem_BatchOpen.Name = "toolStripMenuItem_BatchOpen";
|
toolStripMenuItem_BatchOpen.Name = "toolStripMenuItem_BatchOpen";
|
||||||
toolStripMenuItem_BatchOpen.Size = new Size(254, 34);
|
toolStripMenuItem_BatchOpen.Size = new Size(270, 34);
|
||||||
toolStripMenuItem_BatchOpen.Text = "批量打开(&B)...";
|
toolStripMenuItem_BatchOpen.Text = "批量打开(&B)...";
|
||||||
toolStripMenuItem_BatchOpen.Click += toolStripMenuItem_BatchOpen_Click;
|
toolStripMenuItem_BatchOpen.Click += toolStripMenuItem_BatchOpen_Click;
|
||||||
//
|
//
|
||||||
// toolStripSeparator1
|
// toolStripSeparator1
|
||||||
//
|
//
|
||||||
toolStripSeparator1.Name = "toolStripSeparator1";
|
toolStripSeparator1.Name = "toolStripSeparator1";
|
||||||
toolStripSeparator1.Size = new Size(251, 6);
|
toolStripSeparator1.Size = new Size(267, 6);
|
||||||
//
|
//
|
||||||
// toolStripMenuItem_Export
|
// toolStripMenuItem_Export
|
||||||
//
|
//
|
||||||
|
toolStripMenuItem_Export.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_ExportFrame, toolStripMenuItem_ExportFrames, toolStripMenuItem_ExportGif, toolStripMenuItem_ExportMkv, toolStripMenuItem_ExportMp4, toolStripMenuItem_ExportMov, toolStripMenuItem_ExportWebm });
|
||||||
toolStripMenuItem_Export.Name = "toolStripMenuItem_Export";
|
toolStripMenuItem_Export.Name = "toolStripMenuItem_Export";
|
||||||
toolStripMenuItem_Export.ShortcutKeys = Keys.Control | Keys.S;
|
toolStripMenuItem_Export.Size = new Size(270, 34);
|
||||||
toolStripMenuItem_Export.Size = new Size(254, 34);
|
toolStripMenuItem_Export.Text = "导出(&E)";
|
||||||
toolStripMenuItem_Export.Text = "导出(&E)...";
|
|
||||||
toolStripMenuItem_Export.Click += toolStripMenuItem_Export_Click;
|
|
||||||
//
|
//
|
||||||
// toolStripMenuItem_ExportPreview
|
// toolStripMenuItem_ExportFrame
|
||||||
//
|
//
|
||||||
toolStripMenuItem_ExportPreview.Name = "toolStripMenuItem_ExportPreview";
|
toolStripMenuItem_ExportFrame.Name = "toolStripMenuItem_ExportFrame";
|
||||||
toolStripMenuItem_ExportPreview.Size = new Size(254, 34);
|
toolStripMenuItem_ExportFrame.Size = new Size(270, 34);
|
||||||
toolStripMenuItem_ExportPreview.Text = "导出预览图(&P)...";
|
toolStripMenuItem_ExportFrame.Text = "单帧画面...";
|
||||||
toolStripMenuItem_ExportPreview.Click += toolStripMenuItem_ExportPreview_Click;
|
toolStripMenuItem_ExportFrame.Click += toolStripMenuItem_ExportFrame_Click;
|
||||||
|
//
|
||||||
|
// toolStripMenuItem_ExportFrames
|
||||||
|
//
|
||||||
|
toolStripMenuItem_ExportFrames.Name = "toolStripMenuItem_ExportFrames";
|
||||||
|
toolStripMenuItem_ExportFrames.Size = new Size(270, 34);
|
||||||
|
toolStripMenuItem_ExportFrames.Text = "帧序列...";
|
||||||
|
toolStripMenuItem_ExportFrames.Click += toolStripMenuItem_ExportPng_Click;
|
||||||
|
//
|
||||||
|
// toolStripMenuItem_ExportGif
|
||||||
|
//
|
||||||
|
toolStripMenuItem_ExportGif.Name = "toolStripMenuItem_ExportGif";
|
||||||
|
toolStripMenuItem_ExportGif.Size = new Size(270, 34);
|
||||||
|
toolStripMenuItem_ExportGif.Text = "GIF...";
|
||||||
|
//
|
||||||
|
// toolStripMenuItem_ExportMkv
|
||||||
|
//
|
||||||
|
toolStripMenuItem_ExportMkv.Name = "toolStripMenuItem_ExportMkv";
|
||||||
|
toolStripMenuItem_ExportMkv.Size = new Size(270, 34);
|
||||||
|
toolStripMenuItem_ExportMkv.Text = "MKV";
|
||||||
|
//
|
||||||
|
// toolStripMenuItem_ExportMp4
|
||||||
|
//
|
||||||
|
toolStripMenuItem_ExportMp4.Name = "toolStripMenuItem_ExportMp4";
|
||||||
|
toolStripMenuItem_ExportMp4.Size = new Size(270, 34);
|
||||||
|
toolStripMenuItem_ExportMp4.Text = "MP4...";
|
||||||
|
//
|
||||||
|
// toolStripMenuItem_ExportMov
|
||||||
|
//
|
||||||
|
toolStripMenuItem_ExportMov.Name = "toolStripMenuItem_ExportMov";
|
||||||
|
toolStripMenuItem_ExportMov.Size = new Size(270, 34);
|
||||||
|
toolStripMenuItem_ExportMov.Text = "MOV...";
|
||||||
|
//
|
||||||
|
// toolStripMenuItem_ExportWebm
|
||||||
|
//
|
||||||
|
toolStripMenuItem_ExportWebm.Name = "toolStripMenuItem_ExportWebm";
|
||||||
|
toolStripMenuItem_ExportWebm.Size = new Size(270, 34);
|
||||||
|
toolStripMenuItem_ExportWebm.Text = "WebM...";
|
||||||
//
|
//
|
||||||
// toolStripSeparator2
|
// toolStripSeparator2
|
||||||
//
|
//
|
||||||
toolStripSeparator2.Name = "toolStripSeparator2";
|
toolStripSeparator2.Name = "toolStripSeparator2";
|
||||||
toolStripSeparator2.Size = new Size(251, 6);
|
toolStripSeparator2.Size = new Size(267, 6);
|
||||||
//
|
//
|
||||||
// toolStripMenuItem_Exit
|
// toolStripMenuItem_Exit
|
||||||
//
|
//
|
||||||
toolStripMenuItem_Exit.Name = "toolStripMenuItem_Exit";
|
toolStripMenuItem_Exit.Name = "toolStripMenuItem_Exit";
|
||||||
toolStripMenuItem_Exit.ShortcutKeys = Keys.Alt | Keys.F4;
|
toolStripMenuItem_Exit.ShortcutKeys = Keys.Alt | Keys.F4;
|
||||||
toolStripMenuItem_Exit.Size = new Size(254, 34);
|
toolStripMenuItem_Exit.Size = new Size(270, 34);
|
||||||
toolStripMenuItem_Exit.Text = "退出(&X)";
|
toolStripMenuItem_Exit.Text = "退出(&X)";
|
||||||
toolStripMenuItem_Exit.Click += toolStripMenuItem_Exit_Click;
|
toolStripMenuItem_Exit.Click += toolStripMenuItem_Exit_Click;
|
||||||
//
|
//
|
||||||
@@ -162,7 +204,7 @@
|
|||||||
// toolStripMenuItem_ConvertFileFormat
|
// toolStripMenuItem_ConvertFileFormat
|
||||||
//
|
//
|
||||||
toolStripMenuItem_ConvertFileFormat.Name = "toolStripMenuItem_ConvertFileFormat";
|
toolStripMenuItem_ConvertFileFormat.Name = "toolStripMenuItem_ConvertFileFormat";
|
||||||
toolStripMenuItem_ConvertFileFormat.Size = new Size(270, 34);
|
toolStripMenuItem_ConvertFileFormat.Size = new Size(254, 34);
|
||||||
toolStripMenuItem_ConvertFileFormat.Text = "转换文件格式(&C)...";
|
toolStripMenuItem_ConvertFileFormat.Text = "转换文件格式(&C)...";
|
||||||
toolStripMenuItem_ConvertFileFormat.Click += toolStripMenuItem_ConvertFileFormat_Click;
|
toolStripMenuItem_ConvertFileFormat.Click += toolStripMenuItem_ConvertFileFormat_Click;
|
||||||
//
|
//
|
||||||
@@ -464,7 +506,6 @@
|
|||||||
private ToolStripMenuItem toolStripMenuItem_Open;
|
private ToolStripMenuItem toolStripMenuItem_Open;
|
||||||
private ToolStripMenuItem toolStripMenuItem_Exit;
|
private ToolStripMenuItem toolStripMenuItem_Exit;
|
||||||
private ToolStripSeparator toolStripSeparator1;
|
private ToolStripSeparator toolStripSeparator1;
|
||||||
private ToolStripMenuItem toolStripMenuItem_Export;
|
|
||||||
private ToolStripSeparator toolStripSeparator2;
|
private ToolStripSeparator toolStripSeparator2;
|
||||||
private RichTextBox rtbLog;
|
private RichTextBox rtbLog;
|
||||||
private SplitContainer splitContainer_MainForm;
|
private SplitContainer splitContainer_MainForm;
|
||||||
@@ -490,6 +531,13 @@
|
|||||||
private ToolStripMenuItem toolStripMenuItem_ManageResource;
|
private ToolStripMenuItem toolStripMenuItem_ManageResource;
|
||||||
private ToolStripMenuItem toolStripMenuItem_Tool;
|
private ToolStripMenuItem toolStripMenuItem_Tool;
|
||||||
private ToolStripMenuItem toolStripMenuItem_ConvertFileFormat;
|
private ToolStripMenuItem toolStripMenuItem_ConvertFileFormat;
|
||||||
private ToolStripMenuItem toolStripMenuItem_ExportPreview;
|
private ToolStripMenuItem toolStripMenuItem_Export;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportFrame;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportFrames;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportGif;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportMp4;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportMov;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportMkv;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportWebm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System.Diagnostics;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
using SpineViewer.ExportHelper;
|
||||||
|
|
||||||
namespace SpineViewer
|
namespace SpineViewer
|
||||||
{
|
{
|
||||||
@@ -49,12 +50,12 @@ namespace SpineViewer
|
|||||||
|
|
||||||
private void MainForm_Load(object sender, EventArgs e)
|
private void MainForm_Load(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
spinePreviewer.StartPreview();
|
spinePreviewer.StartRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
|
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||||
{
|
{
|
||||||
spinePreviewer.StopPreview();
|
spinePreviewer.StopRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toolStripMenuItem_Open_Click(object sender, EventArgs e)
|
private void toolStripMenuItem_Open_Click(object sender, EventArgs e)
|
||||||
@@ -67,7 +68,42 @@ namespace SpineViewer
|
|||||||
spineListView.BatchAdd();
|
spineListView.BatchAdd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toolStripMenuItem_Export_Click(object sender, EventArgs e)
|
private void toolStripMenuItem_ExportFrame_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
lock (spineListView.Spines)
|
||||||
|
{
|
||||||
|
if (spineListView.Spines.Count <= 0)
|
||||||
|
{
|
||||||
|
MessageBox.Info("请至少打开一个骨骼文件");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spinePreviewer.IsUpdating)
|
||||||
|
{
|
||||||
|
if (MessageBox.Quest("画面仍在更新,是否手动暂停画面后再导出画面帧?") == DialogResult.OK)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var exportDialog = new Dialogs.ExportDialog()
|
||||||
|
{
|
||||||
|
ExportArgs = new ExportFrameArgs()
|
||||||
|
{
|
||||||
|
Resolution = spinePreviewer.Resolution,
|
||||||
|
View = spinePreviewer.GetView(),
|
||||||
|
RenderSelectedOnly = spinePreviewer.RenderSelectedOnly,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (exportDialog.ShowDialog() != DialogResult.OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var progressDialog = new Dialogs.ProgressDialog();
|
||||||
|
progressDialog.DoWork += ExportFrame_Work;
|
||||||
|
progressDialog.RunWorkerAsync(exportDialog.ExportArgs);
|
||||||
|
progressDialog.ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toolStripMenuItem_ExportPng_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
// TODO: 改成统一导出调用
|
// TODO: 改成统一导出调用
|
||||||
lock (spineListView.Spines)
|
lock (spineListView.Spines)
|
||||||
@@ -89,27 +125,6 @@ namespace SpineViewer
|
|||||||
progressDialog.ShowDialog();
|
progressDialog.ShowDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toolStripMenuItem_ExportPreview_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
lock (spineListView.Spines)
|
|
||||||
{
|
|
||||||
if (spineListView.Spines.Count <= 0)
|
|
||||||
{
|
|
||||||
MessageBox.Info("请至少打开一个骨骼文件");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var saveDialog = new Dialogs.ExportPreviewDialog();
|
|
||||||
if (saveDialog.ShowDialog() != DialogResult.OK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var progressDialog = new Dialogs.ProgressDialog();
|
|
||||||
progressDialog.DoWork += ExportPreview_Work;
|
|
||||||
progressDialog.RunWorkerAsync(saveDialog.Result);
|
|
||||||
progressDialog.ShowDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void toolStripMenuItem_Exit_Click(object sender, EventArgs e)
|
private void toolStripMenuItem_Exit_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
@@ -223,16 +238,15 @@ namespace SpineViewer
|
|||||||
var fps = arguments.Fps;
|
var fps = arguments.Fps;
|
||||||
var timestamp = DateTime.Now.ToString("yyMMddHHmmss");
|
var timestamp = DateTime.Now.ToString("yyMMddHHmmss");
|
||||||
|
|
||||||
var frameArgs = spinePreviewer.GetFrameArgs();
|
|
||||||
var renderSelectedOnly = spinePreviewer.RenderSelectedOnly;
|
var renderSelectedOnly = spinePreviewer.RenderSelectedOnly;
|
||||||
|
|
||||||
var resolution = frameArgs.Resolution;
|
var resolution = spinePreviewer.Resolution;
|
||||||
var tex = new SFML.Graphics.RenderTexture((uint)resolution.Width, (uint)resolution.Height);
|
var tex = new SFML.Graphics.RenderTexture((uint)resolution.Width, (uint)resolution.Height);
|
||||||
tex.SetView(frameArgs.View);
|
tex.SetView(spinePreviewer.GetView());
|
||||||
var delta = 1f / fps;
|
var delta = 1f / fps;
|
||||||
var frameCount = 1 + (int)(duration / delta); // 零帧开始导出
|
var frameCount = 1 + (int)(duration / delta); // 零帧开始导出
|
||||||
|
|
||||||
spinePreviewer.StopPreview();
|
spinePreviewer.StopRender();
|
||||||
|
|
||||||
lock (spineListView.Spines)
|
lock (spineListView.Spines)
|
||||||
{
|
{
|
||||||
@@ -279,31 +293,27 @@ namespace SpineViewer
|
|||||||
Program.Logger.Info("Exporting done: {}/{}", success, frameCount);
|
Program.Logger.Info("Exporting done: {}/{}", success, frameCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
spinePreviewer.StartPreview();
|
spinePreviewer.StartRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExportPreview_Work(object? sender, DoWorkEventArgs e)
|
private void ExportFrame_Work(object? sender, DoWorkEventArgs e)
|
||||||
{
|
{
|
||||||
var worker = sender as BackgroundWorker;
|
var worker = (BackgroundWorker)sender;
|
||||||
var arguments = e.Argument as Dialogs.ExportPreviewDialogResult;
|
var args = (ExportFrameArgs)e.Argument;
|
||||||
|
|
||||||
var outputDir = arguments.OutputDir;
|
using var tex = new SFML.Graphics.RenderTexture((uint)args.Resolution.Width, (uint)args.Resolution.Height);
|
||||||
var imageFormat = arguments.ImageFormat;
|
tex.Clear(SFML.Graphics.Color.Transparent);
|
||||||
var resolution = arguments.Resolution;
|
tex.SetView(args.View);
|
||||||
var padding = arguments.Padding;
|
|
||||||
var dpi = arguments.DPI;
|
|
||||||
var nameSuffix = arguments.NameSuffix;
|
|
||||||
var renderSelectedOnly = spinePreviewer.RenderSelectedOnly;
|
|
||||||
|
|
||||||
var tex = new SFML.Graphics.RenderTexture((uint)resolution.Width, (uint)resolution.Height);
|
|
||||||
|
|
||||||
int success = 0;
|
int success = 0;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
spinePreviewer.StopPreview();
|
spinePreviewer.StopRender();
|
||||||
lock (spineListView.Spines)
|
lock (spineListView.Spines)
|
||||||
{
|
{
|
||||||
var spines = spineListView.Spines;
|
// 根据是否仅渲染选中得到要渲染的模型数组
|
||||||
int totalCount = spines.Count;
|
var spines = spineListView.Spines.Where(sp => !args.RenderSelectedOnly || sp.IsSelected).Reverse().ToArray();
|
||||||
|
|
||||||
|
int totalCount = spines.Length;
|
||||||
worker.ReportProgress(0, $"已处理 0/{totalCount}");
|
worker.ReportProgress(0, $"已处理 0/{totalCount}");
|
||||||
for (int i = 0; i < totalCount; i++)
|
for (int i = 0; i < totalCount; i++)
|
||||||
{
|
{
|
||||||
@@ -314,49 +324,73 @@ namespace SpineViewer
|
|||||||
}
|
}
|
||||||
|
|
||||||
var spine = spines[i];
|
var spine = spines[i];
|
||||||
if (renderSelectedOnly && !spine.IsSelected)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var filename = $"{spine.Name}{nameSuffix}{imageFormat.GetSuffix()}";
|
|
||||||
var savePath = outputDir is null ? Path.Combine(spine.AssetsDir, filename) : Path.Combine(outputDir, filename);
|
|
||||||
|
|
||||||
var tmp = spine.CurrentAnimation;
|
|
||||||
spine.CurrentAnimation = Spine.Spine.EMPTY_ANIMATION;
|
|
||||||
tex.SetView(spine.GetInitView(resolution, padding));
|
|
||||||
tex.Clear(SFML.Graphics.Color.Transparent);
|
|
||||||
tex.Draw(spine);
|
tex.Draw(spine);
|
||||||
|
|
||||||
|
if (args.ExportSingle)
|
||||||
|
{
|
||||||
|
// 导出单个则直接算成功
|
||||||
|
success++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 逐个导出则立即渲染, 并且保存完之后需要清除画面
|
||||||
|
tex.Display();
|
||||||
|
|
||||||
|
var filename = $"{spine.Name}{args.NameSuffix}{args.FileSuffix}";
|
||||||
|
var savePath = args.OutputDir is null ? Path.Combine(spine.AssetsDir, filename) : Path.Combine(args.OutputDir, filename);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var img = new Bitmap(tex.Texture.CopyToBitmap()))
|
||||||
|
{
|
||||||
|
img.SetResolution(args.DPI.Width, args.DPI.Height);
|
||||||
|
img.Save(savePath, args.ImageFormat);
|
||||||
|
}
|
||||||
|
success++;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Program.Logger.Error(ex.ToString());
|
||||||
|
Program.Logger.Error("Failed to save frame {}", spine.SkelPath);
|
||||||
|
error++;
|
||||||
|
}
|
||||||
|
|
||||||
|
tex.Clear(SFML.Graphics.Color.Transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
worker.ReportProgress((int)((i + 1) * 100.0) / totalCount, $"已处理 {i + 1}/{totalCount}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出单个
|
||||||
|
if (args.ExportSingle)
|
||||||
|
{
|
||||||
tex.Display();
|
tex.Display();
|
||||||
spine.CurrentAnimation = tmp;
|
|
||||||
|
var filename = $"{DateTime.Now:yyMMddHHmmss}{args.NameSuffix}{args.FileSuffix}";
|
||||||
|
var savePath = Path.Combine(args.OutputDir, filename);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var img = new Bitmap(tex.Texture.CopyToBitmap()))
|
using (var img = new Bitmap(tex.Texture.CopyToBitmap()))
|
||||||
{
|
{
|
||||||
img.SetResolution(dpi.Width, dpi.Height);
|
img.SetResolution(args.DPI.Width, args.DPI.Height);
|
||||||
img.Save(savePath, imageFormat);
|
img.Save(savePath, args.ImageFormat);
|
||||||
}
|
}
|
||||||
success++;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Program.Logger.Error(ex.ToString());
|
Program.Logger.Error(ex.ToString());
|
||||||
Program.Logger.Error("Failed to save preview {}", spine.SkelPath);
|
Program.Logger.Error("Failed to save single frame");
|
||||||
error++;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
worker.ReportProgress((int)((i + 1) * 100.0) / totalCount, $"已处理 {i + 1}/{totalCount}");
|
else
|
||||||
|
{
|
||||||
|
if (error > 0)
|
||||||
|
Program.Logger.Warn("Frames save {} successfully, {} failed", success, error);
|
||||||
|
else
|
||||||
|
Program.Logger.Info("{} frames saved successfully", success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spinePreviewer.StartPreview();
|
spinePreviewer.StartRender();
|
||||||
|
|
||||||
if (error > 0)
|
|
||||||
{
|
|
||||||
Program.Logger.Warn("Preview save {} successfully, {} failed", success, error);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Program.Logger.Info("{} preview saved successfully", success);
|
|
||||||
}
|
|
||||||
|
|
||||||
Program.LogCurrentMemoryUsage();
|
Program.LogCurrentMemoryUsage();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using SpineViewer.ExportHelper;
|
||||||
|
|
||||||
namespace SpineViewer.Spine
|
namespace SpineViewer.Spine
|
||||||
{
|
{
|
||||||
@@ -346,6 +347,26 @@ namespace SpineViewer.Spine
|
|||||||
[Browsable(false)]
|
[Browsable(false)]
|
||||||
public abstract RectangleF Bounds { get; }
|
public abstract RectangleF Bounds { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始状态下的骨骼包围盒
|
||||||
|
/// </summary>
|
||||||
|
[Browsable(false)]
|
||||||
|
public 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>
|
||||||
@@ -362,7 +383,7 @@ namespace SpineViewer.Spine
|
|||||||
// 除此之外, 似乎还和 tex 的 Dispose 有关
|
// 除此之外, 似乎还和 tex 的 Dispose 有关
|
||||||
// 如果不对 tex 进行 Dispose, 那么不管是否 Draw 都正常不会死锁
|
// 如果不对 tex 进行 Dispose, 那么不管是否 Draw 都正常不会死锁
|
||||||
var tex = new SFML.Graphics.RenderTexture(PREVIEW_WIDTH, PREVIEW_HEIGHT);
|
var tex = new SFML.Graphics.RenderTexture(PREVIEW_WIDTH, PREVIEW_HEIGHT);
|
||||||
tex.SetView(GetInitView(PREVIEW_WIDTH, PREVIEW_HEIGHT));
|
tex.SetView(InitBounds.GetView(PREVIEW_WIDTH, PREVIEW_HEIGHT));
|
||||||
tex.Clear(SFML.Graphics.Color.Transparent);
|
tex.Clear(SFML.Graphics.Color.Transparent);
|
||||||
var tmp = CurrentAnimation;
|
var tmp = CurrentAnimation;
|
||||||
CurrentAnimation = EMPTY_ANIMATION;
|
CurrentAnimation = EMPTY_ANIMATION;
|
||||||
@@ -391,53 +412,6 @@ namespace SpineViewer.Spine
|
|||||||
/// <param name="delta">时间间隔</param>
|
/// <param name="delta">时间间隔</param>
|
||||||
public abstract void Update(float delta);
|
public abstract void Update(float delta);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取初始状态下合适的 View, 参数单位为像素
|
|
||||||
/// </summary>
|
|
||||||
public SFML.Graphics.View GetInitView(Size resolution, Padding padding) =>
|
|
||||||
GetInitView((uint)resolution.Width, (uint)resolution.Height, (uint)padding.Left, (uint)padding.Right, (uint)padding.Top, (uint)padding.Bottom);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取初始状态下合适的 View, 参数单位为像素
|
|
||||||
/// </summary>
|
|
||||||
public SFML.Graphics.View GetInitView(uint width, uint height, Padding padding) =>
|
|
||||||
GetInitView(width, height, (uint)padding.Left, (uint)padding.Right, (uint)padding.Top, (uint)padding.Bottom);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取初始状态下合适的 View, 参数单位为像素
|
|
||||||
/// </summary>
|
|
||||||
public SFML.Graphics.View GetInitView(Size resolution, uint paddingL = 1, uint paddingR = 1, uint paddingT = 1, uint paddingB = 1) =>
|
|
||||||
GetInitView((uint)resolution.Width, (uint)resolution.Height, paddingL, paddingR, paddingT, paddingB);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取初始状态下合适的 View, 参数单位为像素
|
|
||||||
/// </summary>
|
|
||||||
public SFML.Graphics.View GetInitView(uint width, uint height, uint paddingL = 1, uint paddingR = 1, uint paddingT = 1, uint paddingB = 1)
|
|
||||||
{
|
|
||||||
var tmp = CurrentAnimation;
|
|
||||||
CurrentAnimation = EMPTY_ANIMATION;
|
|
||||||
var bounds = Bounds;
|
|
||||||
CurrentAnimation = tmp;
|
|
||||||
|
|
||||||
float sizeX = bounds.Width;
|
|
||||||
float sizeY = bounds.Height;
|
|
||||||
float innerW = width - paddingL - paddingR;
|
|
||||||
float innerH = height - paddingT - paddingB;
|
|
||||||
|
|
||||||
float scale = 1;
|
|
||||||
if ((sizeY / sizeX) < (innerH / innerW))
|
|
||||||
scale = sizeX / innerW; // 相同的 X, 视窗 Y 更大
|
|
||||||
else
|
|
||||||
scale = sizeY / innerH; // 相同的 Y, 视窗 X 更大
|
|
||||||
|
|
||||||
var x = bounds.X + bounds.Width / 2 + ((float)paddingL - (float)paddingR) * scale;
|
|
||||||
var y = bounds.Y + bounds.Height / 2 + ((float)paddingT - (float)paddingB) * scale;
|
|
||||||
var viewX = width * scale;
|
|
||||||
var viewY = height * scale;
|
|
||||||
|
|
||||||
return new(new(x, y), new(viewX, -viewY));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否被选中
|
/// 是否被选中
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user