diff --git a/SpineViewer/Spine/SpineExporter/Exporter.cs b/SpineViewer/Spine/SpineExporter/Exporter.cs index fc8d672..53ebb1e 100644 --- a/SpineViewer/Spine/SpineExporter/Exporter.cs +++ b/SpineViewer/Spine/SpineExporter/Exporter.cs @@ -25,13 +25,18 @@ namespace SpineViewer.Spine.SpineExporter /// /// 可用于文件名的时间戳字符串 /// - protected readonly string timestamp = DateTime.Now.ToString("yyMMddHHmmss"); + protected string timestamp = DateTime.Now.ToString("yyMMddHHmmss"); /// /// 模型包围盒缓存 /// private readonly Dictionary boundsCache = []; + /// + /// 非自动分辨率下导出视图缓存 + /// + private SFML.Graphics.View? viewCache = null; + ~Exporter() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { View.Dispose(); } @@ -52,9 +57,9 @@ namespace SpineViewer.Spine.SpineExporter public Size Resolution { get; set; } = new(100, 100); /// - /// 渲染视窗, 接管对象生命周期 + /// 渲染视窗 /// - public SFML.Graphics.View View { get => view; set { view.Dispose(); view = value; } } + public SFML.Graphics.View View { get => view; set { view.Dispose(); view = new(value); } } private SFML.Graphics.View view = new(); /// @@ -89,7 +94,7 @@ namespace SpineViewer.Spine.SpineExporter /// /// 四周边缘距离, 单位为像素 /// - public Padding Margin + public Padding Margin { get => margin; set @@ -120,6 +125,11 @@ namespace SpineViewer.Spine.SpineExporter } private Padding padding = new(0); + /// + /// 允许内容溢出到边缘和填充区域 + /// + public bool AllowContentOverflow { get; set; } = false; + /// /// 自动分辨率, 将会忽略预览画面的分辨率和视图, 使用模型自身的包围盒 /// @@ -130,19 +140,24 @@ namespace SpineViewer.Spine.SpineExporter /// private SFML.Graphics.RenderTexture GetRenderTexture() { - var x = View.Center.X - View.Size.X / 2; - var y = View.Center.Y - View.Size.Y / 2; - var w = View.Size.X; - var h = View.Size.Y; - var currentBounds = new RectangleF(x, y, w, h); - var bounds = currentBounds.GetResolutionBounds(Resolution, Margin, Padding); + if (viewCache is null) + { + viewCache = new SFML.Graphics.View(View); - using var view = new SFML.Graphics.View(View); - view.Center = new(bounds.X + bounds.Width / 2, bounds.Y + bounds.Height / 2); - view.Size = new(bounds.Width, bounds.Height); + if (AllowContentOverflow) + { + var bounds = View.GetBounds().GetCanvasBounds(Resolution, Margin, Padding); + viewCache.Center = new(bounds.X + bounds.Width / 2, bounds.Y + bounds.Height / 2); + viewCache.Size = new(bounds.Width, bounds.Height); + } + else + { + viewCache.SetViewport(Resolution, Margin, Padding); + } + } var tex = new SFML.Graphics.RenderTexture((uint)(Resolution.Width + Margin.Horizontal), (uint)(Resolution.Height + Margin.Vertical)); - tex.SetView(view); + tex.SetView(viewCache); tex.Clear(SFML.Graphics.Color.Transparent); return tex; } @@ -152,7 +167,16 @@ namespace SpineViewer.Spine.SpineExporter /// //private SFML.Graphics.RenderTexture GetRenderTexture(SpineObject[] spinesToRender) //{ - + // var cacheKey = string.Join("|", spinesToRender.Select(v => v.ID)); + // var bounds = new RectangleF(); + // if (!boundsCache.TryGetValue(cacheKey, out bounds)) + // { + // bounds = spinesToRender[0].GetBounds(); + // foreach (var sp in spinesToRender) + // { + // bounds.X = + // } + // } //} /// @@ -170,7 +194,7 @@ namespace SpineViewer.Spine.SpineExporter // 先将预乘结果准确绘制出来, 注意背景色也应当是预乘的 texPma.Clear(BackgroundColorPma); - foreach (var spine in spinesToRender) texPma.Draw(spine); + foreach (var spine in spinesToRender) { spine.EnableDebug = true; texPma.Draw(spine); } texPma.Display(); // 背景色透明度不为 1 时需要处理反预乘, 否则直接就是结果 @@ -244,13 +268,20 @@ namespace SpineViewer.Spine.SpineExporter { if (Validate() is string err) throw new ArgumentException(err); - boundsCache.Clear(); - var spinesToRender = spines.Where(sp => !RenderSelectedOnly || sp.IsSelected).Reverse().ToArray(); if (spinesToRender.Length > 0) { + boundsCache.Clear(); + viewCache?.Dispose(); + viewCache = null; + + timestamp = DateTime.Now.ToString("yyMMddHHmmss"); // 刷新时间戳 if (IsExportSingle) ExportSingle(spinesToRender, worker); else ExportIndividual(spinesToRender, worker); + + boundsCache.Clear(); + viewCache?.Dispose(); + viewCache = null; } logger.LogCurrentProcessMemoryUsage(); @@ -318,5 +349,11 @@ namespace SpineViewer.Spine.SpineExporter [TypeConverter(typeof(PaddingConverter))] [Category("[0] 导出"), DisplayName("四周填充距离"), Description("画布内部的填充距离 (Padding), 导出的分辨率大小不会发生变化, 但是会留有四周空间")] public Padding Padding { get => Exporter.Padding; set => Exporter.Padding = value; } + + /// + /// 允许内容溢出到边缘和填充区域 + /// + [Category("[0] 导出"), DisplayName("允许内容溢出"), Description("允许内容溢出到边缘和填充区域")] + public bool AllowContentOverflow { get => Exporter.AllowContentOverflow; set => Exporter.AllowContentOverflow = value; } } }