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 { /// /// 日志器 /// 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); } /// /// 可选的进度回调函数 /// /// total: 任务总量 /// done: 已完成量 /// progressText: 需要设置的进度提示文本 /// /// public Action? ProgressReporter { get => _progressReporter; set => _progressReporter = value; } protected Action? _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 } }