208 lines
6.9 KiB
C#
208 lines
6.9 KiB
C#
using NLog;
|
|
using SFML.Graphics;
|
|
using SFML.System;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Spine.Exporters
|
|
{
|
|
/// <summary>
|
|
/// 导出类基类, 提供基本的帧渲染功能
|
|
/// </summary>
|
|
public abstract class BaseExporter : IDisposable
|
|
{
|
|
/// <summary>
|
|
/// 日志器
|
|
/// </summary>
|
|
protected static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
|
|
|
/// <summary>
|
|
/// 用于渲染的画布
|
|
/// </summary>
|
|
protected RenderTexture _renderTexture;
|
|
|
|
/// <summary>
|
|
/// 初始化导出器
|
|
/// </summary>
|
|
/// <param name="width">画布宽像素值</param>
|
|
/// <param name="height">画布高像素值</param>
|
|
public BaseExporter(uint width , uint height)
|
|
{
|
|
// XXX: 强制变成 2 的倍数, 防止像是 yuv420p 这种像素格式报错
|
|
width = width >> 1 << 1;
|
|
height = height >> 1 << 1;
|
|
if (width <= 0 || height <= 0)
|
|
throw new ArgumentException($"Invalid resolution: {width}, {height}");
|
|
_renderTexture = new(width, height);
|
|
_renderTexture.SetActive(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 初始化导出器
|
|
/// </summary>
|
|
public BaseExporter(Vector2u resolution)
|
|
{
|
|
// XXX: 强制变成 2 的倍数, 防止像是 yuv420p 这种像素格式报错
|
|
resolution.X = resolution.X >> 1 << 1;
|
|
resolution.Y = resolution.Y >> 1 << 1;
|
|
if (resolution.X <= 0 || resolution.Y <= 0)
|
|
throw new ArgumentException($"Invalid resolution: {resolution}");
|
|
_renderTexture = new(resolution.X, resolution.Y);
|
|
_renderTexture.SetActive(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 可选的进度回调函数
|
|
/// <list type="number">
|
|
/// <item><c>total</c>: 任务总量</item>
|
|
/// <item><c>done</c>: 已完成量</item>
|
|
/// <item><c>progressText</c>: 需要设置的进度提示文本</item>
|
|
/// </list>
|
|
/// </summary>
|
|
public Action<float, float, string>? ProgressReporter { get => _progressReporter; set => _progressReporter = value; }
|
|
protected Action<float, float, string>? _progressReporter;
|
|
|
|
/// <summary>
|
|
/// 背景颜色
|
|
/// </summary>
|
|
public Color BackgroundColor
|
|
{
|
|
get => _backgroundColor;
|
|
set
|
|
{
|
|
_backgroundColor = value;
|
|
var bcPma = value;
|
|
var a = bcPma.A / 255f;
|
|
bcPma.R = (byte)(bcPma.R * a);
|
|
bcPma.G = (byte)(bcPma.G * a);
|
|
bcPma.B = (byte)(bcPma.B * a);
|
|
_backgroundColorPma = bcPma;
|
|
}
|
|
}
|
|
protected Color _backgroundColor = Color.Black;
|
|
|
|
/// <summary>
|
|
/// 预乘后的背景颜色
|
|
/// </summary>
|
|
protected Color _backgroundColorPma = Color.Black;
|
|
|
|
/// <summary>
|
|
/// 画面分辨率
|
|
/// <inheritdoc cref="RenderTexture.Size"/>
|
|
/// </summary>
|
|
public Vector2u Resolution
|
|
{
|
|
get => _renderTexture.Size;
|
|
set
|
|
{
|
|
// XXX: 强制变成 2 的倍数, 防止像是 yuv420p 这种像素格式报错
|
|
value.X = value.X >> 1 << 1;
|
|
value.Y = value.Y >> 1 << 1;
|
|
if (value.X <= 0 || value.Y <= 0)
|
|
{
|
|
_logger.Warn("Omit invalid exporter resolution: {0}", value);
|
|
return;
|
|
}
|
|
if (_renderTexture.Size != value)
|
|
{
|
|
using var old = _renderTexture;
|
|
using var view = old.GetView();
|
|
var renderTexture = new RenderTexture(value.X, value.Y);
|
|
renderTexture.SetActive(false);
|
|
renderTexture.SetView(view);
|
|
_renderTexture = renderTexture;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// <inheritdoc cref="View.Viewport"/>
|
|
/// </summary>
|
|
public FloatRect Viewport
|
|
{
|
|
get { using var view = _renderTexture.GetView(); return view.Viewport; }
|
|
set { using var view = _renderTexture.GetView(); view.Viewport = value; _renderTexture.SetView(view); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// <inheritdoc cref="View.Center"/>
|
|
/// </summary>
|
|
public Vector2f Center
|
|
{
|
|
get { using var view = _renderTexture.GetView(); return view.Center; }
|
|
set { using var view = _renderTexture.GetView(); view.Center = value; _renderTexture.SetView(view); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// <inheritdoc cref="View.Size"/>
|
|
/// </summary>
|
|
public Vector2f Size
|
|
{
|
|
get { using var view = _renderTexture.GetView(); return view.Size; }
|
|
set { using var view = _renderTexture.GetView(); view.Size = value; _renderTexture.SetView(view); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// <inheritdoc cref="View.Rotation"/>
|
|
/// </summary>
|
|
public float Rotation
|
|
{
|
|
get { using var view = _renderTexture.GetView(); return view.Rotation; }
|
|
set { using var view = _renderTexture.GetView(); view.Rotation = value; _renderTexture.SetView(view); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取的一帧, 结果是预乘的
|
|
/// </summary>
|
|
protected virtual SFMLImageVideoFrame GetFrame(SpineObject[] spines)
|
|
{
|
|
_renderTexture.SetActive(true);
|
|
_renderTexture.Clear(_backgroundColorPma);
|
|
foreach (var sp in spines.Reverse()) _renderTexture.Draw(sp);
|
|
_renderTexture.Display();
|
|
_renderTexture.SetActive(false);
|
|
return new(_renderTexture.Texture.CopyToImage());
|
|
}
|
|
|
|
/// <summary>
|
|
/// 导出给定的模型, 从前往后对应从上往下的渲染顺序
|
|
/// </summary>
|
|
/// <param name="output">输出路径, 一般而言都是文件路径, 少数情况指定的是文件夹</param>
|
|
/// <param name="spines">要导出的模型, 从前往后对应从上往下的渲染顺序</param>
|
|
public abstract void Export(string output, params SpineObject[] spines);
|
|
|
|
#region IDisposable 接口实现
|
|
|
|
private bool _disposed = false;
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (_disposed) return;
|
|
if (disposing)
|
|
{
|
|
_renderTexture.Dispose();
|
|
}
|
|
_disposed = true;
|
|
}
|
|
|
|
~BaseExporter()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
if (_disposed)
|
|
{
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|