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
{
///
/// 导出类基类, 提供基本的帧渲染功能
///
public abstract class BaseExporter : IDisposable
{
///
/// 进度回调函数
///
/// 任务总量
/// 已完成量
/// 需要设置的进度提示文本
public delegate void ProgressReporterHandler(float total, float done, string promptText);
///
/// 日志器
///
protected static readonly Logger _logger = LogManager.GetCurrentClassLogger();
///
/// 用于渲染的画布
///
protected RenderTexture _renderTexture;
///
/// 初始化导出器
///
/// 画布宽像素值
/// 画布高像素值
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);
}
///
/// 初始化导出器
///
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);
}
///
/// 可选的进度回调函数
///
public ProgressReporterHandler? ProgressReporter { get => _progressReporter; set => _progressReporter = value; }
protected ProgressReporterHandler? _progressReporter;
///
/// 背景颜色
///
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;
///
/// 预乘后的背景颜色
///
protected Color _backgroundColorPma = Color.Black;
///
/// 画面分辨率
///
///
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;
}
}
}
///
///
///
public FloatRect Viewport
{
get { using var view = _renderTexture.GetView(); return view.Viewport; }
set { using var view = _renderTexture.GetView(); view.Viewport = value; _renderTexture.SetView(view); }
}
///
///
///
public Vector2f Center
{
get { using var view = _renderTexture.GetView(); return view.Center; }
set { using var view = _renderTexture.GetView(); view.Center = value; _renderTexture.SetView(view); }
}
///
///
///
public Vector2f Size
{
get { using var view = _renderTexture.GetView(); return view.Size; }
set { using var view = _renderTexture.GetView(); view.Size = value; _renderTexture.SetView(view); }
}
///
///
///
public float Rotation
{
get { using var view = _renderTexture.GetView(); return view.Rotation; }
set { using var view = _renderTexture.GetView(); view.Rotation = value; _renderTexture.SetView(view); }
}
///
/// 获取的一帧, 结果是预乘的
///
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());
}
///
/// 导出给定的模型, 从前往后对应从上往下的渲染顺序
///
/// 输出路径, 一般而言都是文件路径, 少数情况指定的是文件夹
/// 要导出的模型, 从前往后对应从上往下的渲染顺序
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
}
}