添加预览画面
This commit is contained in:
68
SpineViewer/src/MainForm.Designer.cs
generated
68
SpineViewer/src/MainForm.Designer.cs
generated
@@ -49,13 +49,11 @@
|
||||
splitContainer_Config = new SplitContainer();
|
||||
groupBox_SkelConfig = new GroupBox();
|
||||
groupBox_PreviewConfig = new GroupBox();
|
||||
propertyGrid_Previewer = new PropertyGrid();
|
||||
groupBox_Preview = new GroupBox();
|
||||
panel_PreviewContainer = new Panel();
|
||||
panel_Preview = new Panel();
|
||||
spinePreviewer = new SpinePreviewer();
|
||||
panel_MainForm = new Panel();
|
||||
openFileDialog_Skel = new OpenFileDialog();
|
||||
openFileDialog_Atlas = new OpenFileDialog();
|
||||
toolTip1 = new ToolTip(components);
|
||||
toolTip = new ToolTip(components);
|
||||
menuStrip.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)splitContainer_MainForm).BeginInit();
|
||||
splitContainer_MainForm.Panel1.SuspendLayout();
|
||||
@@ -75,8 +73,8 @@
|
||||
splitContainer_Config.Panel2.SuspendLayout();
|
||||
splitContainer_Config.SuspendLayout();
|
||||
groupBox_SkelConfig.SuspendLayout();
|
||||
groupBox_PreviewConfig.SuspendLayout();
|
||||
groupBox_Preview.SuspendLayout();
|
||||
panel_PreviewContainer.SuspendLayout();
|
||||
panel_MainForm.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
@@ -266,6 +264,7 @@
|
||||
propertyGrid_Skel.Size = new Size(369, 506);
|
||||
propertyGrid_Skel.TabIndex = 0;
|
||||
propertyGrid_Skel.ToolbarVisible = false;
|
||||
propertyGrid_Skel.PropertyValueChanged += propertyGrid_PropertyValueChanged;
|
||||
//
|
||||
// splitContainer_Config
|
||||
//
|
||||
@@ -304,6 +303,7 @@
|
||||
//
|
||||
// groupBox_PreviewConfig
|
||||
//
|
||||
groupBox_PreviewConfig.Controls.Add(propertyGrid_Previewer);
|
||||
groupBox_PreviewConfig.Dock = DockStyle.Fill;
|
||||
groupBox_PreviewConfig.Location = new Point(0, 0);
|
||||
groupBox_PreviewConfig.Name = "groupBox_PreviewConfig";
|
||||
@@ -312,9 +312,20 @@
|
||||
groupBox_PreviewConfig.TabStop = false;
|
||||
groupBox_PreviewConfig.Text = "画面参数";
|
||||
//
|
||||
// propertyGrid_Previewer
|
||||
//
|
||||
propertyGrid_Previewer.Dock = DockStyle.Fill;
|
||||
propertyGrid_Previewer.HelpVisible = false;
|
||||
propertyGrid_Previewer.Location = new Point(3, 26);
|
||||
propertyGrid_Previewer.Name = "propertyGrid_Previewer";
|
||||
propertyGrid_Previewer.Size = new Size(369, 227);
|
||||
propertyGrid_Previewer.TabIndex = 1;
|
||||
propertyGrid_Previewer.ToolbarVisible = false;
|
||||
propertyGrid_Previewer.PropertyValueChanged += propertyGrid_PropertyValueChanged;
|
||||
//
|
||||
// groupBox_Preview
|
||||
//
|
||||
groupBox_Preview.Controls.Add(panel_PreviewContainer);
|
||||
groupBox_Preview.Controls.Add(spinePreviewer);
|
||||
groupBox_Preview.Dock = DockStyle.Fill;
|
||||
groupBox_Preview.Location = new Point(0, 0);
|
||||
groupBox_Preview.Name = "groupBox_Preview";
|
||||
@@ -323,23 +334,14 @@
|
||||
groupBox_Preview.TabStop = false;
|
||||
groupBox_Preview.Text = "预览画面";
|
||||
//
|
||||
// panel_PreviewContainer
|
||||
// spinePreviewer
|
||||
//
|
||||
panel_PreviewContainer.Controls.Add(panel_Preview);
|
||||
panel_PreviewContainer.Dock = DockStyle.Fill;
|
||||
panel_PreviewContainer.Location = new Point(3, 26);
|
||||
panel_PreviewContainer.Margin = new Padding(0);
|
||||
panel_PreviewContainer.Name = "panel_PreviewContainer";
|
||||
panel_PreviewContainer.Size = new Size(986, 766);
|
||||
panel_PreviewContainer.TabIndex = 1;
|
||||
//
|
||||
// panel_Preview
|
||||
//
|
||||
panel_Preview.BackColor = SystemColors.ControlDark;
|
||||
panel_Preview.Location = new Point(107, 95);
|
||||
panel_Preview.Name = "panel_Preview";
|
||||
panel_Preview.Size = new Size(256, 256);
|
||||
panel_Preview.TabIndex = 0;
|
||||
spinePreviewer.Dock = DockStyle.Fill;
|
||||
spinePreviewer.Location = new Point(3, 26);
|
||||
spinePreviewer.Name = "spinePreviewer";
|
||||
spinePreviewer.Size = new Size(986, 766);
|
||||
spinePreviewer.TabIndex = 0;
|
||||
spinePreviewer.RenderFrame += spinePreviewer_RenderFrame;
|
||||
//
|
||||
// panel_MainForm
|
||||
//
|
||||
@@ -351,17 +353,9 @@
|
||||
panel_MainForm.Size = new Size(1741, 973);
|
||||
panel_MainForm.TabIndex = 4;
|
||||
//
|
||||
// openFileDialog_Skel
|
||||
// toolTip
|
||||
//
|
||||
openFileDialog_Skel.AddExtension = false;
|
||||
openFileDialog_Skel.AddToRecent = false;
|
||||
openFileDialog_Skel.Filter = "skel 文件 (*.skel; *.json)|*.skel;*.json";
|
||||
//
|
||||
// openFileDialog_Atlas
|
||||
//
|
||||
openFileDialog_Atlas.AddExtension = false;
|
||||
openFileDialog_Atlas.AddToRecent = false;
|
||||
openFileDialog_Atlas.Filter = "atlas 文件 (*.atlas)|*.atlas";
|
||||
toolTip.ShowAlways = true;
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
@@ -395,8 +389,8 @@
|
||||
((System.ComponentModel.ISupportInitialize)splitContainer_Config).EndInit();
|
||||
splitContainer_Config.ResumeLayout(false);
|
||||
groupBox_SkelConfig.ResumeLayout(false);
|
||||
groupBox_PreviewConfig.ResumeLayout(false);
|
||||
groupBox_Preview.ResumeLayout(false);
|
||||
panel_PreviewContainer.ResumeLayout(false);
|
||||
panel_MainForm.ResumeLayout(false);
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
@@ -424,12 +418,12 @@
|
||||
private ToolStripMenuItem toolStripMenuItem_About;
|
||||
private ToolStripMenuItem toolStripMenuItem_BatchOpen;
|
||||
private GroupBox groupBox_Preview;
|
||||
private Panel panel_Preview;
|
||||
private Panel panel_PreviewContainer;
|
||||
private OpenFileDialog openFileDialog_Skel;
|
||||
private OpenFileDialog openFileDialog_Atlas;
|
||||
private ToolTip toolTip1;
|
||||
private ToolTip toolTip;
|
||||
private PropertyGrid propertyGrid_Skel;
|
||||
private SpineListView spineListView;
|
||||
private PropertyGrid propertyGrid_Previewer;
|
||||
private SpinePreviewer spinePreviewer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,11 @@ namespace SpineViewer
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
propertyGrid_Previewer.SelectedObject = spinePreviewer.Property;
|
||||
|
||||
InitializeLogConfiguration();
|
||||
spinePreviewer.Property.Resolution = new(1280, 720);
|
||||
spinePreviewer.StartPreview();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -31,10 +35,10 @@ namespace SpineViewer
|
||||
};
|
||||
|
||||
rtbTarget.WordColoringRules.Add(new("[D]", "Gray", "Empty", FontStyle.Bold));
|
||||
rtbTarget.WordColoringRules.Add(new("[I]", "Gray", "Empty", FontStyle.Bold));
|
||||
rtbTarget.WordColoringRules.Add(new("[I]", "DimGray", "Empty", FontStyle.Bold));
|
||||
rtbTarget.WordColoringRules.Add(new("[W]", "DarkOrange", "Empty", FontStyle.Bold));
|
||||
rtbTarget.WordColoringRules.Add(new("[E]", "Red", "Empty", FontStyle.Bold));
|
||||
rtbTarget.WordColoringRules.Add(new("[F]", "Red", "Empty", FontStyle.Bold));
|
||||
rtbTarget.WordColoringRules.Add(new("[F]", "DarkRed", "Empty", FontStyle.Bold));
|
||||
|
||||
LogManager.Configuration.AddTarget(rtbTarget);
|
||||
LogManager.Configuration.AddRule(LogLevel.Debug, LogLevel.Fatal, rtbTarget);
|
||||
@@ -55,8 +59,11 @@ namespace SpineViewer
|
||||
|
||||
private void toolStripMenuItem_Export_Click(object sender, EventArgs e)
|
||||
{
|
||||
var a = new SizeF(10, 100);
|
||||
spineListView.Spines[0].Position = spineListView.Spines[0].Position + a;
|
||||
Program.Logger.Debug("Debug Test");
|
||||
Program.Logger.Info("Info Test");
|
||||
Program.Logger.Warn("Warn Test");
|
||||
Program.Logger.Error("Error Test");
|
||||
Program.Logger.Fatal("Fatal Test");
|
||||
}
|
||||
|
||||
private void toolStripMenuItem_Exit_Click(object sender, EventArgs e)
|
||||
@@ -70,6 +77,26 @@ namespace SpineViewer
|
||||
#endregion
|
||||
|
||||
#region Ԥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
private void spinePreviewer_RenderFrame(object sender, RenderFrameEventArgs e)
|
||||
{
|
||||
var target = e.RenderTarget;
|
||||
var delta = e.Delta;
|
||||
Spine.Spine[] spines = null;
|
||||
|
||||
// <20><>Ҫ<EFBFBD>ڿؼ<DABF><D8BC>߳<EFBFBD><DFB3>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD>dz<EFBFBD><C7B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
if (spineListView.InvokeRequired)
|
||||
spineListView.Invoke(() => spines = spineListView.Spines.ToArray());
|
||||
else
|
||||
spines = spineListView.Spines.ToArray();
|
||||
|
||||
foreach (var spine in spines.Reverse())
|
||||
{
|
||||
spine.Update(delta);
|
||||
target.Draw(spine);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
@@ -84,6 +111,11 @@ namespace SpineViewer
|
||||
ActiveControl = null;
|
||||
}
|
||||
|
||||
private void propertyGrid_PropertyValueChanged(object sender, PropertyValueChangedEventArgs e)
|
||||
{
|
||||
(sender as PropertyGrid).Refresh();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,14 +120,8 @@
|
||||
<metadata name="menuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="openFileDialog_Skel.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>156, 25</value>
|
||||
</metadata>
|
||||
<metadata name="openFileDialog_Atlas.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>404, 23</value>
|
||||
</metadata>
|
||||
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>651, 23</value>
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>187, 20</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>89</value>
|
||||
|
||||
@@ -157,33 +157,33 @@ namespace SpineViewer.Spine
|
||||
/// <summary>
|
||||
/// 缩放比例
|
||||
/// </summary>
|
||||
[Category("空间变换"), DisplayName("缩放比例")]
|
||||
[Category("变换"), DisplayName("缩放比例")]
|
||||
public abstract float Scale { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 位置
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(PointFTypeConverter))]
|
||||
[Category("空间变换"), DisplayName("位置")]
|
||||
[Category("变换"), DisplayName("位置")]
|
||||
public abstract PointF Position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 水平翻转
|
||||
/// </summary>
|
||||
[Category("空间变换"), DisplayName("水平翻转")]
|
||||
[Category("变换"), DisplayName("水平翻转")]
|
||||
public abstract bool FlipX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 垂直翻转
|
||||
/// </summary>
|
||||
[Category("空间变换"), DisplayName("垂直翻转")]
|
||||
[Category("变换"), DisplayName("垂直翻转")]
|
||||
public abstract bool FlipY { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用预乘Alpha
|
||||
/// </summary>
|
||||
[Category("其他"), DisplayName("预乘Alpha通道")]
|
||||
public bool UsePremultipliedAlpha { get; set; }
|
||||
[Category("画面"), DisplayName("预乘Alpha通道")]
|
||||
public bool UsePremultipliedAlpha { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 包含的所有动画名称
|
||||
@@ -202,9 +202,15 @@ namespace SpineViewer.Spine
|
||||
/// 当前动画名称
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(AnimationTypeConverter))]
|
||||
[Category("其他"), DisplayName("当前播放动画"), PropertyTab()]
|
||||
[Category("动画"), DisplayName("当前动画")]
|
||||
public abstract string CurrentAnimation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前动画时长
|
||||
/// </summary>
|
||||
[Category("动画"), DisplayName("当前动画时长")]
|
||||
public float CurrentAnimationDuration { get => GetAnimationDuration(CurrentAnimation); }
|
||||
|
||||
/// <summary>
|
||||
/// 骨骼包围盒
|
||||
/// </summary>
|
||||
|
||||
67
SpineViewer/src/SpinePreviewer.Designer.cs
generated
Normal file
67
SpineViewer/src/SpinePreviewer.Designer.cs
generated
Normal file
@@ -0,0 +1,67 @@
|
||||
namespace SpineViewer
|
||||
{
|
||||
partial class SpinePreviewer
|
||||
{
|
||||
/// <summary>
|
||||
/// 必需的设计器变量。
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region 组件设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
/// 设计器支持所需的方法 - 不要修改
|
||||
/// 使用代码编辑器修改此方法的内容。
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
panel = new Panel();
|
||||
backgroundWorker = new System.ComponentModel.BackgroundWorker();
|
||||
SuspendLayout();
|
||||
//
|
||||
// panel
|
||||
//
|
||||
panel.BackColor = SystemColors.ControlDark;
|
||||
panel.Location = new Point(115, 75);
|
||||
panel.Margin = new Padding(0);
|
||||
panel.Name = "panel";
|
||||
panel.Size = new Size(513, 446);
|
||||
panel.TabIndex = 1;
|
||||
panel.MouseDown += panel_MouseDown;
|
||||
panel.MouseMove += panel_MouseMove;
|
||||
panel.MouseUp += panel_MouseUp;
|
||||
//
|
||||
// backgroundWorker
|
||||
//
|
||||
backgroundWorker.DoWork += backgroundWorker_DoWork;
|
||||
//
|
||||
// SpinePreviewer
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(11F, 24F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
Controls.Add(panel);
|
||||
Name = "SpinePreviewer";
|
||||
Size = new Size(637, 534);
|
||||
SizeChanged += SpinePreviewer_SizeChanged;
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Panel panel;
|
||||
private System.ComponentModel.BackgroundWorker backgroundWorker;
|
||||
}
|
||||
}
|
||||
288
SpineViewer/src/SpinePreviewer.cs
Normal file
288
SpineViewer/src/SpinePreviewer.cs
Normal file
@@ -0,0 +1,288 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Security.Policy;
|
||||
|
||||
namespace SpineViewer
|
||||
{
|
||||
public partial class SpinePreviewer : UserControl
|
||||
{
|
||||
public class PreviewerProperty
|
||||
{
|
||||
public const float ZOOM_MAX = 1000f;
|
||||
public const float ZOOM_MIN = 0.001f;
|
||||
|
||||
private readonly SFML.Graphics.RenderWindow RenderWindow;
|
||||
private readonly Control ContainerControl;
|
||||
|
||||
public PreviewerProperty(SFML.Graphics.RenderWindow renderWindow, Control containerControl)
|
||||
{
|
||||
RenderWindow = renderWindow;
|
||||
ContainerControl = containerControl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出画面分辨率
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(SizeTypeConverter))]
|
||||
[Category("属性"), DisplayName("分辨率")]
|
||||
public Size Resolution
|
||||
{
|
||||
get => resolution;
|
||||
set
|
||||
{
|
||||
if (value.Width <= 0) value.Width = 100;
|
||||
if (value.Height <= 0) value.Height = 100;
|
||||
|
||||
float parentX = ContainerControl.Width;
|
||||
float parentY = ContainerControl.Height;
|
||||
float sizeX = value.Width;
|
||||
float sizeY = value.Height;
|
||||
|
||||
if ((sizeY / sizeX) < (parentY / parentX))
|
||||
{
|
||||
// 相同的 X, 子窗口 Y 更小
|
||||
sizeY = parentX * sizeY / sizeX;
|
||||
sizeX = parentX;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 相同的 Y, 子窗口 X 更小
|
||||
sizeX = parentY * sizeX / sizeY;
|
||||
sizeY = parentY;
|
||||
}
|
||||
|
||||
// 必须通过 SFML 的方法调整窗口
|
||||
RenderWindow.Position = new((int)(parentX - sizeX) / 2, (int)(parentY - sizeY) / 2);
|
||||
RenderWindow.Size = new((uint)sizeX, (uint)sizeY);
|
||||
|
||||
// 将 view 的大小设置成于 resolution 相同的大小, 其余属性都不变
|
||||
var view = RenderWindow.GetView();
|
||||
var signX = Math.Sign(view.Size.X);
|
||||
var signY = Math.Sign(view.Size.Y);
|
||||
view.Size = new(value.Width * signX, value.Height * signY);
|
||||
RenderWindow.SetView(view);
|
||||
|
||||
resolution = value;
|
||||
}
|
||||
}
|
||||
private Size resolution = new(0, 0);
|
||||
|
||||
[TypeConverter(typeof(PointFTypeConverter))]
|
||||
[Category("属性"), DisplayName("画面中心点")]
|
||||
public PointF Center
|
||||
{
|
||||
get
|
||||
{
|
||||
var center = RenderWindow.GetView().Center;
|
||||
return new(center.X, center.Y);
|
||||
}
|
||||
set
|
||||
{
|
||||
var view = RenderWindow.GetView();
|
||||
view.Center = new(value.X, value.Y);
|
||||
RenderWindow.SetView(view);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 画面缩放
|
||||
/// </summary>
|
||||
[Category("属性"), DisplayName("缩放")]
|
||||
public float Zoom
|
||||
{
|
||||
get => resolution.Width / Math.Abs(RenderWindow.GetView().Size.X);
|
||||
set
|
||||
{
|
||||
value = Math.Clamp(value, ZOOM_MIN, ZOOM_MAX);
|
||||
var view = RenderWindow.GetView();
|
||||
var signX = Math.Sign(view.Size.X);
|
||||
var signY = Math.Sign(view.Size.Y);
|
||||
view.Size = new(resolution.Width / value * signX, resolution.Height / value * signY);
|
||||
RenderWindow.SetView(view);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 画面旋转
|
||||
/// </summary>
|
||||
[Category("属性"), DisplayName("旋转")]
|
||||
public float Rotation
|
||||
{
|
||||
get => RenderWindow.GetView().Rotation;
|
||||
set
|
||||
{
|
||||
var view = RenderWindow.GetView();
|
||||
view.Rotation = value;
|
||||
RenderWindow.SetView(view);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 画面旋转
|
||||
/// </summary>
|
||||
[Category("属性"), DisplayName("水平翻转")]
|
||||
public bool FlipX
|
||||
{
|
||||
get => RenderWindow.GetView().Size.X < 0;
|
||||
set
|
||||
{
|
||||
var view = RenderWindow.GetView();
|
||||
var size = view.Size;
|
||||
if (size.X > 0 && value || size.X < 0 && !value)
|
||||
size.X *= -1;
|
||||
view.Size = size;
|
||||
RenderWindow.SetView(view);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 画面旋转
|
||||
/// </summary>
|
||||
[Category("属性"), DisplayName("垂直翻转")]
|
||||
public bool FlipY
|
||||
{
|
||||
get => RenderWindow.GetView().Size.Y < 0;
|
||||
set
|
||||
{
|
||||
var view = RenderWindow.GetView();
|
||||
var size = view.Size;
|
||||
if (size.Y > 0 && value || size.Y < 0 && !value)
|
||||
size.Y *= -1;
|
||||
view.Size = size;
|
||||
RenderWindow.SetView(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 帧渲染事件
|
||||
/// </summary>
|
||||
[Category("自定义"), Description("帧渲染事件")]
|
||||
public event EventHandler<RenderFrameEventArgs>? RenderFrame;
|
||||
private void OnRenderFrame(float delta) { RenderFrame?.Invoke(this, new(RenderWindow, delta)); }
|
||||
|
||||
private readonly SFML.Graphics.RenderWindow RenderWindow;
|
||||
private readonly SFML.System.Clock Clock = new();
|
||||
private readonly SFML.Graphics.Color BackgroundColor = SFML.Graphics.Color.Green;
|
||||
|
||||
[Browsable(false)]
|
||||
public PreviewerProperty Property { get; }
|
||||
|
||||
public SpinePreviewer()
|
||||
{
|
||||
InitializeComponent();
|
||||
RenderWindow = new(panel.Handle);
|
||||
RenderWindow.SetFramerateLimit(30);
|
||||
RenderWindow.SetActive(false);
|
||||
Property = new(RenderWindow, this)
|
||||
{
|
||||
Resolution = new(1280, 720),
|
||||
Center = new(0, 0),
|
||||
FlipY = true
|
||||
};
|
||||
}
|
||||
|
||||
public void StartPreview()
|
||||
{
|
||||
if (!backgroundWorker.IsBusy)
|
||||
backgroundWorker.RunWorkerAsync();
|
||||
}
|
||||
|
||||
public void StopPreview()
|
||||
{
|
||||
if (backgroundWorker.IsBusy)
|
||||
backgroundWorker.CancelAsync();
|
||||
}
|
||||
|
||||
private void SpinePreviewer_SizeChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (RenderWindow is null)
|
||||
return;
|
||||
|
||||
float parentX = Width;
|
||||
float parentY = Height;
|
||||
float sizeX = panel.Width;
|
||||
float sizeY = panel.Height;
|
||||
|
||||
if ((sizeY / sizeX) < (parentY / parentX))
|
||||
{
|
||||
// 相同的 X, 子窗口 Y 更小
|
||||
sizeY = parentX * sizeY / sizeX;
|
||||
sizeX = parentX;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 相同的 Y, 子窗口 X 更小
|
||||
sizeX = parentY * sizeX / sizeY;
|
||||
sizeY = parentY;
|
||||
}
|
||||
|
||||
// 必须通过 SFML 的方法调整窗口
|
||||
RenderWindow.Position = new((int)(parentX - sizeX) / 2, (int)(parentY - sizeY) / 2);
|
||||
RenderWindow.Size = new((uint)sizeX, (uint)sizeY);
|
||||
}
|
||||
|
||||
private void panel_MouseDown(object sender, MouseEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void panel_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void panel_MouseUp(object sender, MouseEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
RenderWindow.SetActive(true);
|
||||
|
||||
while (!backgroundWorker.CancellationPending)
|
||||
{
|
||||
var delta = Clock.ElapsedTime.AsSeconds();
|
||||
Clock.Restart();
|
||||
|
||||
// TODO: 绘制网格线
|
||||
RenderWindow.Clear(BackgroundColor);
|
||||
|
||||
OnRenderFrame(delta);
|
||||
RenderWindow.Display();
|
||||
}
|
||||
|
||||
RenderWindow.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RenderFrame 事件参数
|
||||
/// </summary>
|
||||
public class RenderFrameEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 渲染目标
|
||||
/// </summary>
|
||||
public SFML.Graphics.RenderTarget RenderTarget { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 距离上一帧经过的时间, 单位秒
|
||||
/// </summary>
|
||||
public float Delta { get; }
|
||||
|
||||
public RenderFrameEventArgs(SFML.Graphics.RenderTarget renderTarget, float delta)
|
||||
{
|
||||
RenderTarget = renderTarget;
|
||||
Delta = delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
123
SpineViewer/src/SpinePreviewer.resx
Normal file
123
SpineViewer/src/SpinePreviewer.resx
Normal file
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="backgroundWorker.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
Reference in New Issue
Block a user