From c68a91fe3f2527725f66de6dfbef454a7acfb927 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Mon, 3 Nov 2025 18:09:05 +0800 Subject: [PATCH 01/16] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E7=AD=89=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Spine/Exporters/CustomFFmpegExporter.cs | 2 +- Spine/Exporters/FFmpegVideoExporter.cs | 2 +- Spine/Exporters/FrameSequenceExporter.cs | 2 +- .../Implementations/V21/SpineObjectData21.cs | 8 ++++---- .../Implementations/V34/SpineObjectData34.cs | 8 ++++---- .../Implementations/V35/SpineObjectData35.cs | 8 ++++---- .../Implementations/V36/SpineObjectData36.cs | 8 ++++---- .../Implementations/V37/SpineObjectData37.cs | 8 ++++---- .../Implementations/V38/SpineObjectData38.cs | 8 ++++---- .../Implementations/V40/SpineObjectData40.cs | 8 ++++---- .../Implementations/V41/SpineObjectData41.cs | 8 ++++---- .../Implementations/V42/SpineObjectData42.cs | 8 ++++---- Spine/SpineExtension.cs | 2 +- Spine/SpineObject.cs | 4 ++-- SpineViewer/App.xaml.cs | 20 +++++++++---------- SpineViewer/Utils/JsonHelper.cs | 6 +++--- .../CustomFFmpegExporterViewModel.cs | 4 ++-- .../Exporters/FFmpegVideoExporterViewModel.cs | 4 ++-- .../Exporters/FrameExporterViewModel.cs | 4 ++-- .../FrameSequenceExporterViewModel.cs | 4 ++-- .../MainWindow/ExplorerListViewModel.cs | 12 +++++------ .../MainWindow/PreferenceViewModel.cs | 2 +- .../MainWindow/SFMLRendererViewModel.cs | 2 +- .../MainWindow/SpineObjectListViewModel.cs | 8 ++++---- .../ViewModels/ProgressDialogViewModel.cs | 2 +- SpineViewerCLI/SpineViewerCLI.cs | 2 +- 26 files changed, 77 insertions(+), 77 deletions(-) diff --git a/Spine/Exporters/CustomFFmpegExporter.cs b/Spine/Exporters/CustomFFmpegExporter.cs index 7f420c6..016ae49 100644 --- a/Spine/Exporters/CustomFFmpegExporter.cs +++ b/Spine/Exporters/CustomFFmpegExporter.cs @@ -92,7 +92,7 @@ namespace Spine.Exporters } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to export {0} {1}, {2}", _format, output, ex.Message); } } diff --git a/Spine/Exporters/FFmpegVideoExporter.cs b/Spine/Exporters/FFmpegVideoExporter.cs index b52d0ab..860e397 100644 --- a/Spine/Exporters/FFmpegVideoExporter.cs +++ b/Spine/Exporters/FFmpegVideoExporter.cs @@ -144,7 +144,7 @@ namespace Spine.Exporters } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to export {0} {1}, {2}", _format, output, ex.Message); } } diff --git a/Spine/Exporters/FrameSequenceExporter.cs b/Spine/Exporters/FrameSequenceExporter.cs index 9fd035a..f512bc6 100644 --- a/Spine/Exporters/FrameSequenceExporter.cs +++ b/Spine/Exporters/FrameSequenceExporter.cs @@ -47,7 +47,7 @@ namespace Spine.Exporters } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to save frame {0}, {1}", savePath, ex.Message); } finally diff --git a/Spine/Implementations/V21/SpineObjectData21.cs b/Spine/Implementations/V21/SpineObjectData21.cs index d4a39c4..ad009f2 100644 --- a/Spine/Implementations/V21/SpineObjectData21.cs +++ b/Spine/Implementations/V21/SpineObjectData21.cs @@ -36,7 +36,7 @@ namespace Spine.Implementations.V21 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load atlas '{atlasPath}'"); } @@ -50,7 +50,7 @@ namespace Spine.Implementations.V21 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); } } @@ -62,7 +62,7 @@ namespace Spine.Implementations.V21 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); } } @@ -70,7 +70,7 @@ namespace Spine.Implementations.V21 catch (Exception ex) { _atlas.Dispose(); - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}"); } diff --git a/Spine/Implementations/V34/SpineObjectData34.cs b/Spine/Implementations/V34/SpineObjectData34.cs index ae31a3a..174040f 100644 --- a/Spine/Implementations/V34/SpineObjectData34.cs +++ b/Spine/Implementations/V34/SpineObjectData34.cs @@ -36,7 +36,7 @@ namespace Spine.Implementations.V34 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load atlas '{atlasPath}'"); } @@ -50,7 +50,7 @@ namespace Spine.Implementations.V34 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); } } @@ -62,7 +62,7 @@ namespace Spine.Implementations.V34 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); } } @@ -70,7 +70,7 @@ namespace Spine.Implementations.V34 catch (Exception ex) { _atlas.Dispose(); - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}"); } diff --git a/Spine/Implementations/V35/SpineObjectData35.cs b/Spine/Implementations/V35/SpineObjectData35.cs index 4b29545..23a9a7e 100644 --- a/Spine/Implementations/V35/SpineObjectData35.cs +++ b/Spine/Implementations/V35/SpineObjectData35.cs @@ -36,7 +36,7 @@ namespace Spine.Implementations.V35 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load atlas '{atlasPath}'"); } @@ -50,7 +50,7 @@ namespace Spine.Implementations.V35 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); } } @@ -62,7 +62,7 @@ namespace Spine.Implementations.V35 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); } } @@ -70,7 +70,7 @@ namespace Spine.Implementations.V35 catch (Exception ex) { _atlas.Dispose(); - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}"); } diff --git a/Spine/Implementations/V36/SpineObjectData36.cs b/Spine/Implementations/V36/SpineObjectData36.cs index e7846f7..96cbdef 100644 --- a/Spine/Implementations/V36/SpineObjectData36.cs +++ b/Spine/Implementations/V36/SpineObjectData36.cs @@ -36,7 +36,7 @@ namespace Spine.Implementations.V36 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load atlas '{atlasPath}'"); } @@ -50,7 +50,7 @@ namespace Spine.Implementations.V36 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); } } @@ -62,7 +62,7 @@ namespace Spine.Implementations.V36 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); } } @@ -70,7 +70,7 @@ namespace Spine.Implementations.V36 catch (Exception ex) { _atlas.Dispose(); - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}"); } diff --git a/Spine/Implementations/V37/SpineObjectData37.cs b/Spine/Implementations/V37/SpineObjectData37.cs index b8674b2..db5ce65 100644 --- a/Spine/Implementations/V37/SpineObjectData37.cs +++ b/Spine/Implementations/V37/SpineObjectData37.cs @@ -36,7 +36,7 @@ namespace Spine.Implementations.V37 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load atlas '{atlasPath}'"); } @@ -50,7 +50,7 @@ namespace Spine.Implementations.V37 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); } } @@ -62,7 +62,7 @@ namespace Spine.Implementations.V37 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); } } @@ -70,7 +70,7 @@ namespace Spine.Implementations.V37 catch (Exception ex) { _atlas.Dispose(); - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}"); } diff --git a/Spine/Implementations/V38/SpineObjectData38.cs b/Spine/Implementations/V38/SpineObjectData38.cs index 680d43c..e1069de 100644 --- a/Spine/Implementations/V38/SpineObjectData38.cs +++ b/Spine/Implementations/V38/SpineObjectData38.cs @@ -37,7 +37,7 @@ namespace Spine.Implementations.V38 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load atlas '{atlasPath}'"); } @@ -51,7 +51,7 @@ namespace Spine.Implementations.V38 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); } } @@ -63,7 +63,7 @@ namespace Spine.Implementations.V38 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); } } @@ -71,7 +71,7 @@ namespace Spine.Implementations.V38 catch (Exception ex) { _atlas.Dispose(); - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}"); } diff --git a/Spine/Implementations/V40/SpineObjectData40.cs b/Spine/Implementations/V40/SpineObjectData40.cs index b02a489..7df752e 100644 --- a/Spine/Implementations/V40/SpineObjectData40.cs +++ b/Spine/Implementations/V40/SpineObjectData40.cs @@ -36,7 +36,7 @@ namespace Spine.Implementations.V40 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load atlas '{atlasPath}'"); } @@ -50,7 +50,7 @@ namespace Spine.Implementations.V40 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); } } @@ -62,7 +62,7 @@ namespace Spine.Implementations.V40 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); } } @@ -70,7 +70,7 @@ namespace Spine.Implementations.V40 catch (Exception ex) { _atlas.Dispose(); - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}"); } diff --git a/Spine/Implementations/V41/SpineObjectData41.cs b/Spine/Implementations/V41/SpineObjectData41.cs index 25ede0d..b1ec552 100644 --- a/Spine/Implementations/V41/SpineObjectData41.cs +++ b/Spine/Implementations/V41/SpineObjectData41.cs @@ -36,7 +36,7 @@ namespace Spine.Implementations.V41 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load atlas '{atlasPath}'"); } @@ -50,7 +50,7 @@ namespace Spine.Implementations.V41 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); } } @@ -62,7 +62,7 @@ namespace Spine.Implementations.V41 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); } } @@ -70,7 +70,7 @@ namespace Spine.Implementations.V41 catch (Exception ex) { _atlas.Dispose(); - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}"); } diff --git a/Spine/Implementations/V42/SpineObjectData42.cs b/Spine/Implementations/V42/SpineObjectData42.cs index 95afa35..5a07967 100644 --- a/Spine/Implementations/V42/SpineObjectData42.cs +++ b/Spine/Implementations/V42/SpineObjectData42.cs @@ -36,7 +36,7 @@ namespace Spine.Implementations.V42 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load atlas '{atlasPath}'"); } @@ -50,7 +50,7 @@ namespace Spine.Implementations.V42 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); } } @@ -62,7 +62,7 @@ namespace Spine.Implementations.V42 } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); } } @@ -70,7 +70,7 @@ namespace Spine.Implementations.V42 catch (Exception ex) { _atlas.Dispose(); - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}"); } diff --git a/Spine/SpineExtension.cs b/Spine/SpineExtension.cs index 9d04db8..c8bc5a6 100644 --- a/Spine/SpineExtension.cs +++ b/Spine/SpineExtension.cs @@ -269,7 +269,7 @@ namespace Spine if (hit && LogHitSlots) { - _logger.Debug("Hit ({0}): [{1}]", self.Name, hitSlotName); + _logger.Info("Hit ({0}): [{1}]", self.Name, hitSlotName); } return hit; } diff --git a/Spine/SpineObject.cs b/Spine/SpineObject.cs index c911521..f1aef2d 100644 --- a/Spine/SpineObject.cs +++ b/Spine/SpineObject.cs @@ -82,7 +82,7 @@ namespace Spine } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Warn("Failed to detect version for skel {0}, try all available versions", skelPath); } } @@ -118,7 +118,7 @@ namespace Spine } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load spine with version '{version}'"); } } diff --git a/SpineViewer/App.xaml.cs b/SpineViewer/App.xaml.cs index 9baa531..f8d57b0 100644 --- a/SpineViewer/App.xaml.cs +++ b/SpineViewer/App.xaml.cs @@ -33,8 +33,8 @@ namespace SpineViewer #endif public const string AutoRunFlag = "--autorun"; - private const string MutexName = "__SpineViewerInstance__"; - private const string PipeName = "__SpineViewerPipe__"; + private const string MutexName = $"__{AppName}_Instance__"; + private const string PipeName = $"_{AppName}_Pipe__"; public static readonly string ProcessPath = Environment.ProcessPath; public static readonly string ProcessDirectory = Path.GetDirectoryName(Environment.ProcessPath); @@ -62,7 +62,7 @@ namespace SpineViewer }; TaskScheduler.UnobservedTaskException += (s, e) => { - _logger.Trace(e.Exception.ToString()); + _logger.Debug(e.Exception.ToString()); _logger.Error("Unobserved task exception: {0}", e.Exception.Message); e.SetObserved(); }; @@ -130,7 +130,7 @@ namespace SpineViewer } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to pass command line args to existed instance, {0}", ex.Message); } } @@ -191,7 +191,7 @@ namespace SpineViewer } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to process arguments, {0}", ex.Message); } } @@ -212,7 +212,7 @@ namespace SpineViewer private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { - _logger.Trace(e.Exception.ToString()); + _logger.Debug(e.Exception.ToString()); _logger.Error("Dispatcher unhandled exception: {0}", e.Exception.Message); e.Handled = true; } @@ -231,7 +231,7 @@ namespace SpineViewer } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to query autorun registry key, {0}", ex.Message); return false; } @@ -259,7 +259,7 @@ namespace SpineViewer } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to set autorun registry key, {0}", ex.Message); } } @@ -343,7 +343,7 @@ namespace SpineViewer } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to switch language to {0}, {1}", value, ex.Message); } } @@ -367,7 +367,7 @@ namespace SpineViewer } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to switch skin to {0}, {1}", value, ex.Message); } } diff --git a/SpineViewer/Utils/JsonHelper.cs b/SpineViewer/Utils/JsonHelper.cs index f37c220..93788b2 100644 --- a/SpineViewer/Utils/JsonHelper.cs +++ b/SpineViewer/Utils/JsonHelper.cs @@ -65,7 +65,7 @@ namespace SpineViewer.Utils } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to read json file {0}, {1}", path, ex.Message); } } @@ -86,7 +86,7 @@ namespace SpineViewer.Utils } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to save json file {0}, {1}", path, ex.Message); return false; } @@ -101,7 +101,7 @@ namespace SpineViewer.Utils } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to serialize json object {0}", ex.Message); return string.Empty; } diff --git a/SpineViewer/ViewModels/Exporters/CustomFFmpegExporterViewModel.cs b/SpineViewer/ViewModels/Exporters/CustomFFmpegExporterViewModel.cs index f1afde6..6ad0c87 100644 --- a/SpineViewer/ViewModels/Exporters/CustomFFmpegExporterViewModel.cs +++ b/SpineViewer/ViewModels/Exporters/CustomFFmpegExporterViewModel.cs @@ -112,7 +112,7 @@ namespace SpineViewer.ViewModels.Exporters } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to export {0}, {1}", output, ex.Message); } _vmMain.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None; @@ -169,7 +169,7 @@ namespace SpineViewer.ViewModels.Exporters } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to export {0}, {1}", output, ex.Message); } } diff --git a/SpineViewer/ViewModels/Exporters/FFmpegVideoExporterViewModel.cs b/SpineViewer/ViewModels/Exporters/FFmpegVideoExporterViewModel.cs index 446639e..f41b325 100644 --- a/SpineViewer/ViewModels/Exporters/FFmpegVideoExporterViewModel.cs +++ b/SpineViewer/ViewModels/Exporters/FFmpegVideoExporterViewModel.cs @@ -149,7 +149,7 @@ namespace SpineViewer.ViewModels.Exporters } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to export {0}, {1}", output, ex.Message); } _vmMain.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None; @@ -206,7 +206,7 @@ namespace SpineViewer.ViewModels.Exporters } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to export {0}, {1}", output, ex.Message); } } diff --git a/SpineViewer/ViewModels/Exporters/FrameExporterViewModel.cs b/SpineViewer/ViewModels/Exporters/FrameExporterViewModel.cs index 839805c..70196e7 100644 --- a/SpineViewer/ViewModels/Exporters/FrameExporterViewModel.cs +++ b/SpineViewer/ViewModels/Exporters/FrameExporterViewModel.cs @@ -85,7 +85,7 @@ namespace SpineViewer.ViewModels.Exporters } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to export {0}, {1}", output, ex.Message); } } @@ -121,7 +121,7 @@ namespace SpineViewer.ViewModels.Exporters } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to export {0}, {1}", output, ex.Message); } done++; diff --git a/SpineViewer/ViewModels/Exporters/FrameSequenceExporterViewModel.cs b/SpineViewer/ViewModels/Exporters/FrameSequenceExporterViewModel.cs index cb547d5..0ef7507 100644 --- a/SpineViewer/ViewModels/Exporters/FrameSequenceExporterViewModel.cs +++ b/SpineViewer/ViewModels/Exporters/FrameSequenceExporterViewModel.cs @@ -76,7 +76,7 @@ namespace SpineViewer.ViewModels.Exporters } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to export {0}, {1}", output, ex.Message); } _vmMain.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None; @@ -133,7 +133,7 @@ namespace SpineViewer.ViewModels.Exporters } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to export {0}, {1}", output, ex.Message); } } diff --git a/SpineViewer/ViewModels/MainWindow/ExplorerListViewModel.cs b/SpineViewer/ViewModels/MainWindow/ExplorerListViewModel.cs index 3a56496..bcb6813 100644 --- a/SpineViewer/ViewModels/MainWindow/ExplorerListViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/ExplorerListViewModel.cs @@ -169,7 +169,7 @@ namespace SpineViewer.ViewModels.MainWindow } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to generate preview: {0}, {1}", m.PreviewFilePath, ex.Message); } _logger.LogCurrentProcessMemoryUsage(); @@ -221,7 +221,7 @@ namespace SpineViewer.ViewModels.MainWindow } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to generate preview: {0}, {1}", m.PreviewFilePath, ex.Message); error++; } @@ -261,7 +261,7 @@ namespace SpineViewer.ViewModels.MainWindow } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to delete preview: {0}, {1}", m.PreviewFilePath, ex.Message); } } @@ -302,7 +302,7 @@ namespace SpineViewer.ViewModels.MainWindow } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to delete preview: {0}, {1}", m.PreviewFilePath, ex.Message); error++; } @@ -340,7 +340,7 @@ namespace SpineViewer.ViewModels.MainWindow } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to enumerate files in dir: {0}, {1}", _currentDirectory, ex.Message); } } @@ -408,7 +408,7 @@ namespace SpineViewer.ViewModels.MainWindow } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Warn("Failed to load preview image for {0}, {1}", FullPath, ex.Message); return null; } diff --git a/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs b/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs index 5b07df6..9f2a823 100644 --- a/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs @@ -76,7 +76,7 @@ namespace SpineViewer.ViewModels.MainWindow catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to load some prefereneces, {0}", ex.Message); } } diff --git a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs index e70f138..829df00 100644 --- a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs @@ -573,7 +573,7 @@ namespace SpineViewer.ViewModels.MainWindow } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Fatal("Render task stopped, {0}", ex.Message); MessagePopupService.Error(ex.ToString()); } diff --git a/SpineViewer/ViewModels/MainWindow/SpineObjectListViewModel.cs b/SpineViewer/ViewModels/MainWindow/SpineObjectListViewModel.cs index a6cda79..eb325f1 100644 --- a/SpineViewer/ViewModels/MainWindow/SpineObjectListViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/SpineObjectListViewModel.cs @@ -213,7 +213,7 @@ namespace SpineViewer.ViewModels.MainWindow } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to load: {0}, {1}", skelPath, ex.Message); } return false; @@ -340,7 +340,7 @@ namespace SpineViewer.ViewModels.MainWindow } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to reload spine {0}, {1}", sp.SkelPath, ex.Message); } } @@ -401,7 +401,7 @@ namespace SpineViewer.ViewModels.MainWindow catch (Exception ex) { error++; - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to reload spine {0}, {1}", sp.SkelPath, ex.Message); } } @@ -718,7 +718,7 @@ namespace SpineViewer.ViewModels.MainWindow } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to load: {0}, {1}", cfg.SkelPath, ex.Message); } return false; diff --git a/SpineViewer/ViewModels/ProgressDialogViewModel.cs b/SpineViewer/ViewModels/ProgressDialogViewModel.cs index 7bc3f9f..6c2a9cc 100644 --- a/SpineViewer/ViewModels/ProgressDialogViewModel.cs +++ b/SpineViewer/ViewModels/ProgressDialogViewModel.cs @@ -35,7 +35,7 @@ namespace SpineViewer.ViewModels } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Error("Failed to finish work: {0}, {1}", _title, ex.Message); WorkFinished?.Invoke(this, false); } diff --git a/SpineViewerCLI/SpineViewerCLI.cs b/SpineViewerCLI/SpineViewerCLI.cs index 9bcbea3..36c2110 100644 --- a/SpineViewerCLI/SpineViewerCLI.cs +++ b/SpineViewerCLI/SpineViewerCLI.cs @@ -42,7 +42,7 @@ namespace SpineViewerCLI } catch (Exception ex) { - _logger.Trace(ex.ToString()); + _logger.Debug(ex.ToString()); _logger.Fatal("Failed to execute, {0}", ex.Message); return -1; } From 7eb140a0306aec6e046779410718ab36d5d18eeb Mon Sep 17 00:00:00 2001 From: ww-rm Date: Mon, 3 Nov 2025 18:13:01 +0800 Subject: [PATCH 02/16] =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpineViewer/App.xaml.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/SpineViewer/App.xaml.cs b/SpineViewer/App.xaml.cs index f8d57b0..f121b0c 100644 --- a/SpineViewer/App.xaml.cs +++ b/SpineViewer/App.xaml.cs @@ -2,6 +2,7 @@ using NLog; using SpineViewer.Natives; using SpineViewer.Resources; +using SpineViewer.Services; using SpineViewer.ViewModels.MainWindow; using SpineViewer.Views; using System.Collections.Frozen; @@ -58,13 +59,16 @@ namespace SpineViewer AppDomain.CurrentDomain.UnhandledException += (s, e) => { + _logger.Debug(e.ExceptionObject.ToString()); _logger.Fatal("Unhandled exception: {0}", e.ExceptionObject); + MessagePopupService.Error(e.ExceptionObject.ToString()); }; TaskScheduler.UnobservedTaskException += (s, e) => { _logger.Debug(e.Exception.ToString()); - _logger.Error("Unobserved task exception: {0}", e.Exception.Message); + _logger.Fatal("Unobserved task exception: {0}", e.Exception.Message); e.SetObserved(); + MessagePopupService.Error(e.Exception.ToString()); }; // 单例模式加 IPC 通信 @@ -213,8 +217,9 @@ namespace SpineViewer private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { _logger.Debug(e.Exception.ToString()); - _logger.Error("Dispatcher unhandled exception: {0}", e.Exception.Message); + _logger.Fatal("Dispatcher unhandled exception: {0}", e.Exception.Message); e.Handled = true; + MessagePopupService.Error(e.Exception.ToString()); } public bool AutoRun From 246f70fd4dae3ed5dfd238a026fcf34159772bf2 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Tue, 4 Nov 2025 18:29:27 +0800 Subject: [PATCH 03/16] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=BB=B6=E8=BF=9F?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E6=97=B6=E9=97=B4=E4=B8=BA1s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpineViewer/Views/MainWindow.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpineViewer/Views/MainWindow.xaml.cs b/SpineViewer/Views/MainWindow.xaml.cs index f705ca1..e57ddf1 100644 --- a/SpineViewer/Views/MainWindow.xaml.cs +++ b/SpineViewer/Views/MainWindow.xaml.cs @@ -47,7 +47,7 @@ public partial class MainWindow : Window private readonly List _userStateWatchers = []; private DispatcherTimer _saveUserStateTimer; - private readonly TimeSpan _saveTimerDelay = TimeSpan.FromSeconds(3); + private readonly TimeSpan _saveTimerDelay = TimeSpan.FromSeconds(1); public bool RootGridCol0Folded { From b17f3bec793b8f619fb18c9f6a4f090e49aabb6a Mon Sep 17 00:00:00 2001 From: ww-rm Date: Fri, 7 Nov 2025 18:40:30 +0800 Subject: [PATCH 04/16] add comment --- SpineViewer/Views/MainWindow.xaml.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/SpineViewer/Views/MainWindow.xaml.cs b/SpineViewer/Views/MainWindow.xaml.cs index e57ddf1..6dd44c8 100644 --- a/SpineViewer/Views/MainWindow.xaml.cs +++ b/SpineViewer/Views/MainWindow.xaml.cs @@ -440,6 +440,7 @@ public partial class MainWindow : Window private void SFMLRendererViewModel_PropertyChanged(object? sender, PropertyChangedEventArgs e) { + // XXX: 资源管理器重启后窗口会有问题无法重新显示, 需要重启应用, 否则要重新创建窗口 if (e.PropertyName == nameof(SFMLRendererViewModel.WallpaperView)) { var wnd = _wallpaperRenderWindow; From 32c826a3db874428fd8b13c97ffe149afdbdec2e Mon Sep 17 00:00:00 2001 From: ww-rm Date: Fri, 7 Nov 2025 23:20:05 +0800 Subject: [PATCH 05/16] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dlabel=E4=B8=8D=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E4=B8=8B=E5=88=92=E7=BA=BF=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpineViewer/Resources/Theme.xaml | 40 +++++++++++++------ SpineViewer/Views/AboutDialog.xaml | 2 +- SpineViewer/Views/DiagnosticsDialog.xaml | 2 +- .../CustomFFmpegExporterDialog.xaml | 2 +- .../FFmpegVideoExporterDialog.xaml | 2 +- .../ExporterDialogs/FrameExporterDialog.xaml | 2 +- .../FrameSequenceExporterDialog.xaml | 2 +- SpineViewer/Views/MainWindow.xaml | 6 +-- SpineViewer/Views/PreferenceDialog.xaml | 2 +- 9 files changed, 37 insertions(+), 23 deletions(-) diff --git a/SpineViewer/Resources/Theme.xaml b/SpineViewer/Resources/Theme.xaml index fb363f5..c338f5a 100644 --- a/SpineViewer/Resources/Theme.xaml +++ b/SpineViewer/Resources/Theme.xaml @@ -11,7 +11,7 @@ - - - - - - - - + + diff --git a/SpineViewer/Views/DiagnosticsDialog.xaml b/SpineViewer/Views/DiagnosticsDialog.xaml index ea046ad..ba58e9b 100644 --- a/SpineViewer/Views/DiagnosticsDialog.xaml +++ b/SpineViewer/Views/DiagnosticsDialog.xaml @@ -24,7 +24,7 @@ - diff --git a/SpineViewer/Views/ExporterDialogs/CustomFFmpegExporterDialog.xaml b/SpineViewer/Views/ExporterDialogs/CustomFFmpegExporterDialog.xaml index 4f2867c..53b2b65 100644 --- a/SpineViewer/Views/ExporterDialogs/CustomFFmpegExporterDialog.xaml +++ b/SpineViewer/Views/ExporterDialogs/CustomFFmpegExporterDialog.xaml @@ -31,7 +31,7 @@ - diff --git a/SpineViewer/Views/ExporterDialogs/FFmpegVideoExporterDialog.xaml b/SpineViewer/Views/ExporterDialogs/FFmpegVideoExporterDialog.xaml index 91e3efa..25fbda1 100644 --- a/SpineViewer/Views/ExporterDialogs/FFmpegVideoExporterDialog.xaml +++ b/SpineViewer/Views/ExporterDialogs/FFmpegVideoExporterDialog.xaml @@ -31,7 +31,7 @@ - diff --git a/SpineViewer/Views/ExporterDialogs/FrameExporterDialog.xaml b/SpineViewer/Views/ExporterDialogs/FrameExporterDialog.xaml index 2da3a98..f309a2a 100644 --- a/SpineViewer/Views/ExporterDialogs/FrameExporterDialog.xaml +++ b/SpineViewer/Views/ExporterDialogs/FrameExporterDialog.xaml @@ -31,7 +31,7 @@ - diff --git a/SpineViewer/Views/ExporterDialogs/FrameSequenceExporterDialog.xaml b/SpineViewer/Views/ExporterDialogs/FrameSequenceExporterDialog.xaml index 6688872..73bbb27 100644 --- a/SpineViewer/Views/ExporterDialogs/FrameSequenceExporterDialog.xaml +++ b/SpineViewer/Views/ExporterDialogs/FrameSequenceExporterDialog.xaml @@ -31,7 +31,7 @@ - diff --git a/SpineViewer/Views/MainWindow.xaml b/SpineViewer/Views/MainWindow.xaml index 06f20bf..6f323d7 100644 --- a/SpineViewer/Views/MainWindow.xaml +++ b/SpineViewer/Views/MainWindow.xaml @@ -239,7 +239,7 @@ TabStripPlacement="Bottom" DataContext="{Binding SpineObjectTabViewModel}"> - @@ -695,7 +695,7 @@ - @@ -955,7 +955,7 @@ - diff --git a/SpineViewer/Views/PreferenceDialog.xaml b/SpineViewer/Views/PreferenceDialog.xaml index 9384a2c..f962604 100644 --- a/SpineViewer/Views/PreferenceDialog.xaml +++ b/SpineViewer/Views/PreferenceDialog.xaml @@ -31,7 +31,7 @@ - From d6ca3cca92a018aa2d377ac0e5627a8863d4250c Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sat, 8 Nov 2025 00:09:55 +0800 Subject: [PATCH 06/16] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=9E=E6=97=B6?= =?UTF-8?q?=E5=B8=A7=E7=8E=87=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpineViewer/Resources/Strings/en.xaml | 3 ++ SpineViewer/Resources/Strings/ja.xaml | 3 ++ SpineViewer/Resources/Strings/zh.xaml | 3 ++ .../MainWindow/SFMLRendererViewModel.cs | 28 ++++++++++++--- SpineViewer/Views/MainWindow.xaml | 35 ++++++++++++++----- SpineViewer/Views/MainWindow.xaml.cs | 4 +-- 6 files changed, 60 insertions(+), 16 deletions(-) diff --git a/SpineViewer/Resources/Strings/en.xaml b/SpineViewer/Resources/Strings/en.xaml index e4bdbfd..5f979db 100644 --- a/SpineViewer/Resources/Strings/en.xaml +++ b/SpineViewer/Resources/Strings/en.xaml @@ -140,6 +140,9 @@ Forward 10 Frames Window/Fullscreen; F11 + + Real-time FPS: {0:F1} + OK Cancel diff --git a/SpineViewer/Resources/Strings/ja.xaml b/SpineViewer/Resources/Strings/ja.xaml index 16559c7..9d607b7 100644 --- a/SpineViewer/Resources/Strings/ja.xaml +++ b/SpineViewer/Resources/Strings/ja.xaml @@ -140,6 +140,9 @@ 10フレーム進める ウィンドウ/フルスクリーン; F11 + + リアルタイムFPS:{0:F1} + OK キャンセル diff --git a/SpineViewer/Resources/Strings/zh.xaml b/SpineViewer/Resources/Strings/zh.xaml index 9fc695c..12959e2 100644 --- a/SpineViewer/Resources/Strings/zh.xaml +++ b/SpineViewer/Resources/Strings/zh.xaml @@ -140,6 +140,9 @@ 快进 10 帧 窗口/全屏; F11 + + 实时帧率:{0:F1} + 确认 取消 diff --git a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs index 829df00..857212d 100644 --- a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs @@ -156,6 +156,12 @@ namespace SpineViewer.ViewModels.MainWindow set => SetProperty(_renderer.MaxFps, value, v => _renderer.MaxFps = _wallpaperRenderer.MaxFps = value); } + public float RealTimeFps => _realTimeFps; + private float _realTimeFps; + + private float _accumFpsTime; + private int _accumFpsCount; + public float Speed { get => _speed; @@ -469,19 +475,31 @@ namespace SpineViewer.ViewModels.MainWindow _wallpaperRenderer.SetActive(true); _renderer.SetActive(true); - float delta; + float frameDelta; + float updateDelta; while (!_cancelToken?.IsCancellationRequested ?? false) { - delta = _clock.ElapsedTime.AsSeconds(); + updateDelta = frameDelta = _clock.ElapsedTime.AsSeconds(); _clock.Restart(); + // 计算实时帧率, 1 秒刷新一次 + _accumFpsCount++; + _accumFpsTime += frameDelta; + if (_accumFpsTime > 1f) + { + _realTimeFps = _accumFpsCount / _accumFpsTime; + _accumFpsTime = 0f; + _accumFpsCount = 0; + OnPropertyChanged(nameof(RealTimeFps)); + } + // 停止更新的时候只是时间不前进, 但是坐标变换还是要更新, 否则无法移动对象 - if (!_isUpdating) delta = 0; + if (!_isUpdating) updateDelta = 0; // 加上要快进的量 lock (_forwardDeltaLock) { - delta += _forwardDelta; + updateDelta += _forwardDelta; _forwardDelta = 0; } @@ -543,7 +561,7 @@ namespace SpineViewer.ViewModels.MainWindow if (_cancelToken?.IsCancellationRequested ?? true) break; // 提前中止 sp.Update(0); // 避免物理效果出现问题 - sp.Update(delta * _speed); + sp.Update(updateDelta * _speed); if (_vmMain.IsVisible) { diff --git a/SpineViewer/Views/MainWindow.xaml b/SpineViewer/Views/MainWindow.xaml index 6f323d7..7e46fa2 100644 --- a/SpineViewer/Views/MainWindow.xaml +++ b/SpineViewer/Views/MainWindow.xaml @@ -912,14 +912,16 @@ - - - - - - - - + + + + + + + + + + - + + + + + + + + + + + + + + + + diff --git a/SpineViewer/Views/MainWindow.xaml.cs b/SpineViewer/Views/MainWindow.xaml.cs index 6dd44c8..07aa442 100644 --- a/SpineViewer/Views/MainWindow.xaml.cs +++ b/SpineViewer/Views/MainWindow.xaml.cs @@ -695,7 +695,7 @@ public partial class MainWindow : Window _renderPanelButtonsPopupContainer.Child = _renderPanelButtonsPanel; _loggerBoxContainer.Child = null; - _loggerBoxPopupContainer.Child = _loggerRichTextBox; + _loggerBoxPopupContainer.Child = _loggerBoxPanel; } private void SwitchToNormalLayout() @@ -705,7 +705,7 @@ public partial class MainWindow : Window HandyControl.Controls.IconElement.SetGeometry(_fullScreenButton, AppResource.Geo_ArrowsMaximize); _loggerBoxPopupContainer.Child = null; - _loggerBoxContainer.Child = _loggerRichTextBox; + _loggerBoxContainer.Child = _loggerBoxPanel; _renderPanelButtonsPopupContainer.Child = null; _renderPanelButtonsContainer.Child = _renderPanelButtonsPanel; From 763d2e295e991bb1436c8b992791ad137a46c248 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sat, 8 Nov 2025 17:17:25 +0800 Subject: [PATCH 07/16] =?UTF-8?q?=E6=8B=86=E5=88=86=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E5=B8=A7=E5=92=8C=E6=B8=B2=E6=9F=93=E5=B8=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MainWindow/SFMLRendererViewModel.cs | 254 ++++++++++-------- 1 file changed, 143 insertions(+), 111 deletions(-) diff --git a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs index 857212d..6385575 100644 --- a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs @@ -50,7 +50,7 @@ namespace SpineViewer.ViewModels.MainWindow /// /// 坐标轴顶点缓冲区 /// - private readonly SFML.Graphics.VertexArray _axisVertices = new(SFML.Graphics.PrimitiveType.Lines, 2); // XXX: 暂时未使用 Dispose 释放 + private readonly SFML.Graphics.VertexArray _axisVertices = new(SFML.Graphics.PrimitiveType.Lines, 4); // XXX: 暂时未使用 Dispose 释放 /// /// 帧间隔计时器 @@ -87,6 +87,12 @@ namespace SpineViewer.ViewModels.MainWindow _models = _vmMain.SpineObjects; _renderer = _vmMain.SFMLRenderer; _wallpaperRenderer = _vmMain.WallpaperRenderer; + + // 画一个很长的坐标轴, 用 1e9 比较合适 + _axisVertices[0] = new(new(-1e9f, 0), _axisColor); + _axisVertices[1] = new(new(1e9f, 0), _axisColor); + _axisVertices[2] = new(new(0, -1e9f), _axisColor); + _axisVertices[3] = new(new(0, 1e9f), _axisColor); } /// @@ -194,7 +200,7 @@ namespace SpineViewer.ViewModels.MainWindow /// private SFML.Graphics.Color _axisColor = SFML.Graphics.Color.White; - public string BackgroundImagePath + public string? BackgroundImagePath { get => _backgroundImagePath; set => SetProperty(_backgroundImagePath, value, v => @@ -243,7 +249,7 @@ namespace SpineViewer.ViewModels.MainWindow } }); } - private string _backgroundImagePath; + private string? _backgroundImagePath; public Stretch BackgroundImageMode { @@ -475,118 +481,14 @@ namespace SpineViewer.ViewModels.MainWindow _wallpaperRenderer.SetActive(true); _renderer.SetActive(true); - float frameDelta; - float updateDelta; + float delta; while (!_cancelToken?.IsCancellationRequested ?? false) { - updateDelta = frameDelta = _clock.ElapsedTime.AsSeconds(); + delta = _clock.ElapsedTime.AsSeconds(); _clock.Restart(); - // 计算实时帧率, 1 秒刷新一次 - _accumFpsCount++; - _accumFpsTime += frameDelta; - if (_accumFpsTime > 1f) - { - _realTimeFps = _accumFpsCount / _accumFpsTime; - _accumFpsTime = 0f; - _accumFpsCount = 0; - OnPropertyChanged(nameof(RealTimeFps)); - } - - // 停止更新的时候只是时间不前进, 但是坐标变换还是要更新, 否则无法移动对象 - if (!_isUpdating) updateDelta = 0; - - // 加上要快进的量 - lock (_forwardDeltaLock) - { - updateDelta += _forwardDelta; - _forwardDelta = 0; - } - - using var view = _renderer.GetView(); - _wallpaperRenderer.SetView(view); - - if (_vmMain.IsVisible) _renderer.Clear(_backgroundColor); - if (_wallpaperView) _wallpaperRenderer.Clear(_backgroundColor); - - // 渲染背景 - lock (_bgLock) - { - if (_backgroundImageSprite is not null) - { - var bg = _backgroundImageSprite; - var viewSize = view.Size; - var bgSize = bg.Texture.Size; - var scaleX = Math.Abs(viewSize.X / bgSize.X); - var scaleY = Math.Abs(viewSize.Y / bgSize.Y); - var signX = Math.Sign(viewSize.X); - var signY = Math.Sign(viewSize.Y); - if (_backgroundImageMode == Stretch.None) - { - scaleX = scaleY = 1f / _renderer.Zoom; - } - else if (_backgroundImageMode == Stretch.Uniform) - { - scaleX = scaleY = Math.Min(scaleX, scaleY); - } - else if (_backgroundImageMode == Stretch.UniformToFill) - { - scaleX = scaleY = Math.Max(scaleX, scaleY); - } - bg.Scale = new(signX * scaleX, signY * scaleY); - bg.Position = view.Center; - bg.Rotation = view.Rotation; - - if (_vmMain.IsVisible) _renderer.Draw(bg); - if (_wallpaperView) _wallpaperRenderer.Draw(bg); - } - } - - if (_showAxis && _vmMain.IsVisible) - { - // 画一个很长的坐标轴, 用 1e9 比较合适 - _axisVertices[0] = new(new(-1e9f, 0), _axisColor); - _axisVertices[1] = new(new(1e9f, 0), _axisColor); - _renderer.Draw(_axisVertices); - _axisVertices[0] = new(new(0, -1e9f), _axisColor); - _axisVertices[1] = new(new(0, 1e9f), _axisColor); - _renderer.Draw(_axisVertices); - } - - // 渲染 Spine - lock (_models.Lock) - { - foreach (var sp in _models.Where(sp => sp.IsShown && (!_renderSelectedOnly || sp.IsSelected)).Reverse()) - { - if (_cancelToken?.IsCancellationRequested ?? true) break; // 提前中止 - - sp.Update(0); // 避免物理效果出现问题 - sp.Update(updateDelta * _speed); - - if (_vmMain.IsVisible) - { - // 为选中对象绘制一个半透明背景 - if (sp.IsSelected) - { - var rc = sp.GetCurrentBounds().ToFloatRect(); - _selectedBackgroundVertices[0] = new(new(rc.Left, rc.Top), _selectedBackgroundColor); - _selectedBackgroundVertices[1] = new(new(rc.Left + rc.Width, rc.Top), _selectedBackgroundColor); - _selectedBackgroundVertices[2] = new(new(rc.Left + rc.Width, rc.Top + rc.Height), _selectedBackgroundColor); - _selectedBackgroundVertices[3] = new(new(rc.Left, rc.Top + rc.Height), _selectedBackgroundColor); - _renderer.Draw(_selectedBackgroundVertices); - } - - // 仅在预览画面临时启用调试模式 - sp.EnableDebug = true; - _renderer.Draw(sp); - sp.EnableDebug = false; - } - if (_wallpaperView) _wallpaperRenderer.Draw(sp); - } - } - - if (_vmMain.IsVisible) _renderer.Display(); - if (_wallpaperView) _wallpaperRenderer.Display(); + UpdateLogicFrame(delta); + UpdateRenderFrame(); } } catch (Exception ex) @@ -602,6 +504,136 @@ namespace SpineViewer.ViewModels.MainWindow } } + private void UpdateLogicFrame(float delta) + { + // 计算实时帧率, 1 秒刷新一次 + _accumFpsCount++; + _accumFpsTime += delta; + if (_accumFpsTime > 1f) + { + _realTimeFps = _accumFpsCount / _accumFpsTime; + _accumFpsTime = 0f; + _accumFpsCount = 0; + OnPropertyChanged(nameof(RealTimeFps)); + } + + // 停止更新的时候只是时间不前进, 但是坐标变换还是要更新, 否则无法移动对象 + if (!_isUpdating) delta = 0; + + // 加上要快进的量 + lock (_forwardDeltaLock) + { + delta += _forwardDelta; + _forwardDelta = 0; + } + + // 更新模型对象时间 + lock (_models.Lock) + { + foreach (var sp in _models.Where(sp => sp.IsShown && (!_renderSelectedOnly || sp.IsSelected)).Reverse()) + { + if (_cancelToken?.IsCancellationRequested ?? true) break; // 提前中止 + + sp.Update(0); // 避免物理效果出现问题 + sp.Update(delta * _speed); + } + } + } + + private void UpdateRenderFrame() + { + // 同步视图 + if (_wallpaperView) + { + using var view = _renderer.GetView(); + _wallpaperRenderer.SetView(view); + } + + // 更新背景图位置和缩放 + lock (_bgLock) + { + if (_backgroundImageSprite is not null) + { + using var view = _renderer.GetView(); + var bg = _backgroundImageSprite; + var viewSize = view.Size; + var bgSize = bg.Texture.Size; + var scaleX = Math.Abs(viewSize.X / bgSize.X); + var scaleY = Math.Abs(viewSize.Y / bgSize.Y); + var signX = Math.Sign(viewSize.X); + var signY = Math.Sign(viewSize.Y); + if (_backgroundImageMode == Stretch.None) + { + scaleX = scaleY = 1f / _renderer.Zoom; + } + else if (_backgroundImageMode == Stretch.Uniform) + { + scaleX = scaleY = Math.Min(scaleX, scaleY); + } + else if (_backgroundImageMode == Stretch.UniformToFill) + { + scaleX = scaleY = Math.Max(scaleX, scaleY); + } + bg.Scale = new(signX * scaleX, signY * scaleY); + bg.Position = view.Center; + bg.Rotation = view.Rotation; + } + } + + // 清除背景 + if (_vmMain.IsVisible) _renderer.Clear(_backgroundColor); + if (_wallpaperView) _wallpaperRenderer.Clear(_backgroundColor); + + // 渲染背景 + lock (_bgLock) + { + if (_backgroundImageSprite is not null) + { + if (_vmMain.IsVisible) _renderer.Draw(_backgroundImageSprite); + if (_wallpaperView) _wallpaperRenderer.Draw(_backgroundImageSprite); + } + } + + // 渲染坐标轴 + if (_showAxis && _vmMain.IsVisible) + { + _renderer.Draw(_axisVertices); + } + + // 渲染 Spine + lock (_models.Lock) + { + foreach (var sp in _models.Where(sp => sp.IsShown && (!_renderSelectedOnly || sp.IsSelected)).Reverse()) + { + if (_cancelToken?.IsCancellationRequested ?? true) break; // 提前中止 + + if (_vmMain.IsVisible) + { + // 为选中对象绘制一个半透明背景 + if (sp.IsSelected) + { + var rc = sp.GetCurrentBounds().ToFloatRect(); + _selectedBackgroundVertices[0] = new(new(rc.Left, rc.Top), _selectedBackgroundColor); + _selectedBackgroundVertices[1] = new(new(rc.Left + rc.Width, rc.Top), _selectedBackgroundColor); + _selectedBackgroundVertices[2] = new(new(rc.Left + rc.Width, rc.Top + rc.Height), _selectedBackgroundColor); + _selectedBackgroundVertices[3] = new(new(rc.Left, rc.Top + rc.Height), _selectedBackgroundColor); + _renderer.Draw(_selectedBackgroundVertices); + } + + // 仅在预览画面临时启用调试模式 + sp.EnableDebug = true; + _renderer.Draw(sp); + sp.EnableDebug = false; + } + if (_wallpaperView) _wallpaperRenderer.Draw(sp); + } + } + + // 显示内容 + if (_vmMain.IsVisible) _renderer.Display(); + if (_wallpaperView) _wallpaperRenderer.Display(); + } + public RendererWorkspaceConfigModel WorkspaceConfig { get From 849f1813be0f3a53f63a252ef778fbb7b7652b4c Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sat, 8 Nov 2025 17:34:20 +0800 Subject: [PATCH 08/16] =?UTF-8?q?=E6=8B=86=E5=88=86=E5=8F=8C=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E7=BA=BF=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MainWindow/SFMLRendererViewModel.cs | 127 ++++++++++++------ 1 file changed, 88 insertions(+), 39 deletions(-) diff --git a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs index 6385575..22142ef 100644 --- a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs @@ -61,6 +61,7 @@ namespace SpineViewer.ViewModels.MainWindow /// 渲染任务 /// private Task? _renderTask = null; + private Task? _wallpaperRenderTask = null; private CancellationTokenSource? _cancelToken = null; /// @@ -459,26 +460,29 @@ namespace SpineViewer.ViewModels.MainWindow { if (_renderTask is not null) return; _cancelToken = new(); - _renderTask = new Task(RenderTask, _cancelToken.Token, TaskCreationOptions.LongRunning); + _renderTask = new(RenderTask, _cancelToken.Token, TaskCreationOptions.LongRunning); + _wallpaperRenderTask = new(WallpaperRenderTask, _cancelToken.Token, TaskCreationOptions.LongRunning); _renderTask.Start(); + _wallpaperRenderTask.Start(); IsUpdating = true; } public void StopRender() { IsUpdating = false; - if (_renderTask is null || _cancelToken is null) return; + if (_cancelToken is null || _renderTask is null || _wallpaperRenderTask is null) return; _cancelToken.Cancel(); + _wallpaperRenderTask.Wait(); _renderTask.Wait(); - _cancelToken = null; + _wallpaperRenderTask = null; _renderTask = null; + _cancelToken = null; } private void RenderTask() { try { - _wallpaperRenderer.SetActive(true); _renderer.SetActive(true); float delta; @@ -500,7 +504,6 @@ namespace SpineViewer.ViewModels.MainWindow finally { _renderer.SetActive(false); - _wallpaperRenderer.SetActive(false); } } @@ -538,16 +541,6 @@ namespace SpineViewer.ViewModels.MainWindow sp.Update(delta * _speed); } } - } - - private void UpdateRenderFrame() - { - // 同步视图 - if (_wallpaperView) - { - using var view = _renderer.GetView(); - _wallpaperRenderer.SetView(view); - } // 更新背景图位置和缩放 lock (_bgLock) @@ -579,23 +572,27 @@ namespace SpineViewer.ViewModels.MainWindow bg.Rotation = view.Rotation; } } + } + + private void UpdateRenderFrame() + { + if (!_vmMain.IsVisible) + return; // 清除背景 - if (_vmMain.IsVisible) _renderer.Clear(_backgroundColor); - if (_wallpaperView) _wallpaperRenderer.Clear(_backgroundColor); + _renderer.Clear(_backgroundColor); // 渲染背景 lock (_bgLock) { if (_backgroundImageSprite is not null) { - if (_vmMain.IsVisible) _renderer.Draw(_backgroundImageSprite); - if (_wallpaperView) _wallpaperRenderer.Draw(_backgroundImageSprite); + _renderer.Draw(_backgroundImageSprite); } } // 渲染坐标轴 - if (_showAxis && _vmMain.IsVisible) + if (_showAxis) { _renderer.Draw(_axisVertices); } @@ -607,31 +604,83 @@ namespace SpineViewer.ViewModels.MainWindow { if (_cancelToken?.IsCancellationRequested ?? true) break; // 提前中止 - if (_vmMain.IsVisible) + // 为选中对象绘制一个半透明背景 + if (sp.IsSelected) { - // 为选中对象绘制一个半透明背景 - if (sp.IsSelected) - { - var rc = sp.GetCurrentBounds().ToFloatRect(); - _selectedBackgroundVertices[0] = new(new(rc.Left, rc.Top), _selectedBackgroundColor); - _selectedBackgroundVertices[1] = new(new(rc.Left + rc.Width, rc.Top), _selectedBackgroundColor); - _selectedBackgroundVertices[2] = new(new(rc.Left + rc.Width, rc.Top + rc.Height), _selectedBackgroundColor); - _selectedBackgroundVertices[3] = new(new(rc.Left, rc.Top + rc.Height), _selectedBackgroundColor); - _renderer.Draw(_selectedBackgroundVertices); - } - - // 仅在预览画面临时启用调试模式 - sp.EnableDebug = true; - _renderer.Draw(sp); - sp.EnableDebug = false; + var rc = sp.GetCurrentBounds().ToFloatRect(); + _selectedBackgroundVertices[0] = new(new(rc.Left, rc.Top), _selectedBackgroundColor); + _selectedBackgroundVertices[1] = new(new(rc.Left + rc.Width, rc.Top), _selectedBackgroundColor); + _selectedBackgroundVertices[2] = new(new(rc.Left + rc.Width, rc.Top + rc.Height), _selectedBackgroundColor); + _selectedBackgroundVertices[3] = new(new(rc.Left, rc.Top + rc.Height), _selectedBackgroundColor); + _renderer.Draw(_selectedBackgroundVertices); } - if (_wallpaperView) _wallpaperRenderer.Draw(sp); + + // 仅在预览画面临时启用调试模式 + sp.EnableDebug = true; + _renderer.Draw(sp); + sp.EnableDebug = false; } } // 显示内容 - if (_vmMain.IsVisible) _renderer.Display(); - if (_wallpaperView) _wallpaperRenderer.Display(); + _renderer.Display(); + } + + private void WallpaperRenderTask() + { + try + { + _wallpaperRenderer.SetActive(true); + while (!_cancelToken?.IsCancellationRequested ?? false) + { + if (!_wallpaperView) + { + Thread.Sleep(10); + continue; + } + + // 同步视图 + using var view = _renderer.GetView(); + _wallpaperRenderer.SetView(view); + + // 清除背景 + _wallpaperRenderer.Clear(_backgroundColor); + + // 渲染背景 + lock (_bgLock) + { + if (_backgroundImageSprite is not null) + { + _wallpaperRenderer.Draw(_backgroundImageSprite); + } + } + + // 渲染 Spine + lock (_models.Lock) + { + foreach (var sp in _models.Where(sp => sp.IsShown && (!_renderSelectedOnly || sp.IsSelected)).Reverse()) + { + if (_cancelToken?.IsCancellationRequested ?? true) + break; // 提前中止 + + _wallpaperRenderer.Draw(sp); + } + } + + // 显示渲染 + _wallpaperRenderer.Display(); + } + } + catch (Exception ex) + { + _logger.Debug(ex.ToString()); + _logger.Fatal("Wallpaper render task stopped, {0}", ex.Message); + MessagePopupService.Error(ex.ToString()); + } + finally + { + _wallpaperRenderer.SetActive(false); + } } public RendererWorkspaceConfigModel WorkspaceConfig From fb319e09d836f94ee869a6b14935ffe2fe063900 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sat, 8 Nov 2025 17:42:11 +0800 Subject: [PATCH 09/16] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs index 22142ef..cd0f664 100644 --- a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs @@ -577,7 +577,11 @@ namespace SpineViewer.ViewModels.MainWindow private void UpdateRenderFrame() { if (!_vmMain.IsVisible) + { + // 必须休眠一会, 否则会空转影响整体渲染循环 + Thread.Sleep(1); return; + } // 清除背景 _renderer.Clear(_backgroundColor); From 8e771fbaa4865a41bb5ba9688d49dbe2cf7bc273 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sat, 8 Nov 2025 19:17:09 +0800 Subject: [PATCH 10/16] =?UTF-8?q?=E9=87=8D=E6=9E=84Win32Natives?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpineViewer.sln | 6 +++++ SpineViewer/App.xaml.cs | 8 +++--- SpineViewer/Extensions/WpfExtension.cs | 26 ++++++++++++++----- SpineViewer/SpineViewer.csproj | 1 + .../MainWindow/PreferenceViewModel.cs | 1 - SpineViewer/Views/AboutDialog.xaml.cs | 8 +++--- SpineViewer/Views/DiagnosticsDialog.xaml.cs | 8 +++--- .../CustomFFmpegExporterDialog.xaml.cs | 8 +++--- .../FFmpegVideoExporterDialog.xaml.cs | 8 +++--- .../FrameExporterDialog.xaml.cs | 8 +++--- .../FrameSequenceExporterDialog.xaml.cs | 8 +++--- SpineViewer/Views/MainWindow.xaml.cs | 14 +++++----- SpineViewer/Views/PreferenceDialog.xaml.cs | 8 +++--- SpineViewer/Views/ProgressDialog.xaml.cs | 8 +++--- .../Natives => Win32Natives}/Dwmapi.cs | 11 ++++---- .../Natives => Win32Natives}/Gdi32.cs | 2 +- .../Natives => Win32Natives}/Shell32.cs | 2 +- .../Natives => Win32Natives}/User32.cs | 2 +- Win32Natives/Win32Natives.csproj | 14 ++++++++++ 19 files changed, 91 insertions(+), 60 deletions(-) rename {SpineViewer/Natives => Win32Natives}/Dwmapi.cs (81%) rename {SpineViewer/Natives => Win32Natives}/Gdi32.cs (96%) rename {SpineViewer/Natives => Win32Natives}/Shell32.cs (96%) rename {SpineViewer/Natives => Win32Natives}/User32.cs (99%) create mode 100644 Win32Natives/Win32Natives.csproj diff --git a/SpineViewer.sln b/SpineViewer.sln index cb6c58c..9cb9c0c 100644 --- a/SpineViewer.sln +++ b/SpineViewer.sln @@ -43,6 +43,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpineRuntime35", "SpineRunt EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpineRuntime34", "SpineRuntimes\SpineRuntime34\SpineRuntime34.csproj", "{348605F7-3FF4-1DE0-4B91-7AEFE7BC5C55}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Win32Natives", "Win32Natives\Win32Natives.csproj", "{48864874-7307-950E-A667-62BB66357C62}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -105,6 +107,10 @@ Global {348605F7-3FF4-1DE0-4B91-7AEFE7BC5C55}.Debug|x64.Build.0 = Debug|x64 {348605F7-3FF4-1DE0-4B91-7AEFE7BC5C55}.Release|x64.ActiveCfg = Release|x64 {348605F7-3FF4-1DE0-4B91-7AEFE7BC5C55}.Release|x64.Build.0 = Release|x64 + {48864874-7307-950E-A667-62BB66357C62}.Debug|x64.ActiveCfg = Debug|x64 + {48864874-7307-950E-A667-62BB66357C62}.Debug|x64.Build.0 = Debug|x64 + {48864874-7307-950E-A667-62BB66357C62}.Release|x64.ActiveCfg = Release|x64 + {48864874-7307-950E-A667-62BB66357C62}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SpineViewer/App.xaml.cs b/SpineViewer/App.xaml.cs index f121b0c..dd403ee 100644 --- a/SpineViewer/App.xaml.cs +++ b/SpineViewer/App.xaml.cs @@ -1,6 +1,6 @@ using Microsoft.Win32; using NLog; -using SpineViewer.Natives; +using Win32Natives; using SpineViewer.Resources; using SpineViewer.Services; using SpineViewer.ViewModels.MainWindow; @@ -15,6 +15,7 @@ using System.IO.Pipes; using System.Reflection; using System.Windows; using System.Windows.Interop; +using SpineViewer.Extensions; namespace SpineViewer { @@ -365,9 +366,8 @@ namespace SpineViewer { Resources.MergedDictionaries.Add(new() { Source = new(uri, UriKind.Relative) }); Resources.MergedDictionaries.Add(new() { Source = new("Resources/Theme.xaml", UriKind.Relative) }); - var hwnd = new WindowInteropHelper(Current.MainWindow).Handle; - Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText); - Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region); + Current.MainWindow.SetWindowTextColor(AppResource.Color_PrimaryText); + Current.MainWindow.SetWindowCaptionColor(AppResource.Color_Region); _skin = value; } catch (Exception ex) diff --git a/SpineViewer/Extensions/WpfExtension.cs b/SpineViewer/Extensions/WpfExtension.cs index 9ce86e0..ddfd3da 100644 --- a/SpineViewer/Extensions/WpfExtension.cs +++ b/SpineViewer/Extensions/WpfExtension.cs @@ -1,6 +1,4 @@ -using SFML.Graphics; -using SFML.System; -using SkiaSharp; +using SkiaSharp; using System; using System.Collections.Generic; using System.IO; @@ -9,29 +7,31 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows; +using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; +using Win32Natives; namespace SpineViewer.Extensions { public static class WpfExtension { - public static FloatRect ToFloatRect(this Rect self) + public static SFML.Graphics.FloatRect ToFloatRect(this Rect self) { return new((float)self.X, (float)self.Y, (float)self.Width, (float)self.Height); } - public static Vector2f ToVector2f(this Size self) + public static SFML.System.Vector2f ToVector2f(this Size self) { return new((float)self.Width, (float)self.Height); } - public static Vector2u ToVector2u(this Size self) + public static SFML.System.Vector2u ToVector2u(this Size self) { return new((uint)self.Width, (uint)self.Height); } - public static Vector2i ToVector2i(this Size self) + public static SFML.System.Vector2i ToVector2i(this Size self) { return new((int)self.Width, (int)self.Height); } @@ -60,6 +60,18 @@ namespace SpineViewer.Extensions return wb; } + public static void SetWindowTextColor(this Window self, Color color) + { + var hwnd = new WindowInteropHelper(self).Handle; + Dwmapi.SetWindowTextColor(hwnd, color.R, color.G, color.B); + } + + public static void SetWindowCaptionColor(this Window self, Color color) + { + var hwnd = new WindowInteropHelper(self).Handle; + Dwmapi.SetWindowCaptionColor(hwnd, color.R, color.G, color.B); + } + //public static void SaveToFile(this BitmapSource bitmap, string path) //{ // var ext = Path.GetExtension(path)?.ToLowerInvariant(); diff --git a/SpineViewer/SpineViewer.csproj b/SpineViewer/SpineViewer.csproj index 03b940e..b5ff95c 100644 --- a/SpineViewer/SpineViewer.csproj +++ b/SpineViewer/SpineViewer.csproj @@ -41,5 +41,6 @@ + diff --git a/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs b/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs index 9f2a823..a7efe9c 100644 --- a/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs @@ -5,7 +5,6 @@ using NLog; using Spine; using Spine.Implementations; using SpineViewer.Models; -using SpineViewer.Natives; using SpineViewer.Services; using SpineViewer.Utils; using System; diff --git a/SpineViewer/Views/AboutDialog.xaml.cs b/SpineViewer/Views/AboutDialog.xaml.cs index f390768..a98bc35 100644 --- a/SpineViewer/Views/AboutDialog.xaml.cs +++ b/SpineViewer/Views/AboutDialog.xaml.cs @@ -1,4 +1,4 @@ -using SpineViewer.Natives; +using SpineViewer.Extensions; using SpineViewer.Resources; using System; using System.Collections.Generic; @@ -14,6 +14,7 @@ using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; +using Win32Natives; namespace SpineViewer.Views { @@ -30,9 +31,8 @@ namespace SpineViewer.Views private void AboutDialog_SourceInitialized(object? sender, EventArgs e) { - var hwnd = new WindowInteropHelper(this).Handle; - Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText); - Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region); + this.SetWindowTextColor(AppResource.Color_PrimaryText); + this.SetWindowCaptionColor(AppResource.Color_Region); } } } diff --git a/SpineViewer/Views/DiagnosticsDialog.xaml.cs b/SpineViewer/Views/DiagnosticsDialog.xaml.cs index 72ca5aa..c79e895 100644 --- a/SpineViewer/Views/DiagnosticsDialog.xaml.cs +++ b/SpineViewer/Views/DiagnosticsDialog.xaml.cs @@ -1,4 +1,4 @@ -using SpineViewer.Natives; +using SpineViewer.Extensions; using SpineViewer.Resources; using System; using System.Collections.Generic; @@ -14,6 +14,7 @@ using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; +using Win32Natives; namespace SpineViewer.Views { @@ -30,9 +31,8 @@ namespace SpineViewer.Views private void DiagnosticsDialog_SourceInitialized(object? sender, EventArgs e) { - var hwnd = new WindowInteropHelper(this).Handle; - Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText); - Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region); + this.SetWindowTextColor(AppResource.Color_PrimaryText); + this.SetWindowCaptionColor(AppResource.Color_Region); } } } diff --git a/SpineViewer/Views/ExporterDialogs/CustomFFmpegExporterDialog.xaml.cs b/SpineViewer/Views/ExporterDialogs/CustomFFmpegExporterDialog.xaml.cs index eda8ae4..efce9e0 100644 --- a/SpineViewer/Views/ExporterDialogs/CustomFFmpegExporterDialog.xaml.cs +++ b/SpineViewer/Views/ExporterDialogs/CustomFFmpegExporterDialog.xaml.cs @@ -1,4 +1,4 @@ -using SpineViewer.Natives; +using Win32Natives; using SpineViewer.Resources; using SpineViewer.Services; using SpineViewer.ViewModels.Exporters; @@ -16,6 +16,7 @@ using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; +using SpineViewer.Extensions; namespace SpineViewer.Views.ExporterDialogs { @@ -32,9 +33,8 @@ namespace SpineViewer.Views.ExporterDialogs private void CustomFFmpegExporterDialog_SourceInitialized(object? sender, EventArgs e) { - var hwnd = new WindowInteropHelper(this).Handle; - Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText); - Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region); + this.SetWindowTextColor(AppResource.Color_PrimaryText); + this.SetWindowCaptionColor(AppResource.Color_Region); } private void ButtonOK_Click(object sender, RoutedEventArgs e) diff --git a/SpineViewer/Views/ExporterDialogs/FFmpegVideoExporterDialog.xaml.cs b/SpineViewer/Views/ExporterDialogs/FFmpegVideoExporterDialog.xaml.cs index b4dbaaa..9b92f6a 100644 --- a/SpineViewer/Views/ExporterDialogs/FFmpegVideoExporterDialog.xaml.cs +++ b/SpineViewer/Views/ExporterDialogs/FFmpegVideoExporterDialog.xaml.cs @@ -1,4 +1,4 @@ -using SpineViewer.Natives; +using SpineViewer.Extensions; using SpineViewer.Resources; using SpineViewer.Services; using SpineViewer.ViewModels.Exporters; @@ -16,6 +16,7 @@ using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; +using Win32Natives; namespace SpineViewer.Views.ExporterDialogs { @@ -32,9 +33,8 @@ namespace SpineViewer.Views.ExporterDialogs private void FFmpegVideoExporterDialog_SourceInitialized(object? sender, EventArgs e) { - var hwnd = new WindowInteropHelper(this).Handle; - Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText); - Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region); + this.SetWindowTextColor(AppResource.Color_PrimaryText); + this.SetWindowCaptionColor(AppResource.Color_Region); } private void ButtonOK_Click(object sender, RoutedEventArgs e) diff --git a/SpineViewer/Views/ExporterDialogs/FrameExporterDialog.xaml.cs b/SpineViewer/Views/ExporterDialogs/FrameExporterDialog.xaml.cs index b34058f..e29e695 100644 --- a/SpineViewer/Views/ExporterDialogs/FrameExporterDialog.xaml.cs +++ b/SpineViewer/Views/ExporterDialogs/FrameExporterDialog.xaml.cs @@ -1,4 +1,4 @@ -using SpineViewer.Natives; +using SpineViewer.Extensions; using SpineViewer.Resources; using SpineViewer.Services; using SpineViewer.ViewModels.Exporters; @@ -16,6 +16,7 @@ using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; +using Win32Natives; namespace SpineViewer.Views.ExporterDialogs { @@ -32,9 +33,8 @@ namespace SpineViewer.Views.ExporterDialogs private void FrameExporterDialog_SourceInitialized(object? sender, EventArgs e) { - var hwnd = new WindowInteropHelper(this).Handle; - Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText); - Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region); + this.SetWindowTextColor(AppResource.Color_PrimaryText); + this.SetWindowCaptionColor(AppResource.Color_Region); } private void ButtonOK_Click(object sender, RoutedEventArgs e) diff --git a/SpineViewer/Views/ExporterDialogs/FrameSequenceExporterDialog.xaml.cs b/SpineViewer/Views/ExporterDialogs/FrameSequenceExporterDialog.xaml.cs index 1ed0c47..db4c9d4 100644 --- a/SpineViewer/Views/ExporterDialogs/FrameSequenceExporterDialog.xaml.cs +++ b/SpineViewer/Views/ExporterDialogs/FrameSequenceExporterDialog.xaml.cs @@ -1,4 +1,4 @@ -using SpineViewer.Natives; +using SpineViewer.Extensions; using SpineViewer.Resources; using SpineViewer.Services; using SpineViewer.ViewModels.Exporters; @@ -16,6 +16,7 @@ using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; +using Win32Natives; namespace SpineViewer.Views.ExporterDialogs { @@ -32,9 +33,8 @@ namespace SpineViewer.Views.ExporterDialogs private void FrameSequenceExporterDialog_SourceInitialized(object? sender, EventArgs e) { - var hwnd = new WindowInteropHelper(this).Handle; - Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText); - Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region); + this.SetWindowTextColor(AppResource.Color_PrimaryText); + this.SetWindowCaptionColor(AppResource.Color_Region); } private void ButtonOK_Click(object sender, RoutedEventArgs e) diff --git a/SpineViewer/Views/MainWindow.xaml.cs b/SpineViewer/Views/MainWindow.xaml.cs index 07aa442..cf59900 100644 --- a/SpineViewer/Views/MainWindow.xaml.cs +++ b/SpineViewer/Views/MainWindow.xaml.cs @@ -1,8 +1,8 @@ using NLog; using SFMLRenderer; using Spine; +using SpineViewer.Extensions; using SpineViewer.Models; -using SpineViewer.Natives; using SpineViewer.Resources; using SpineViewer.Services; using SpineViewer.Utils; @@ -24,6 +24,7 @@ using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; using System.Windows.Threading; +using Win32Natives; namespace SpineViewer.Views; @@ -98,13 +99,13 @@ public partial class MainWindow : Window // Initialize Wallpaper RenderWindow _wallpaperRenderWindow = new(new(1, 1), "SpineViewerWallpaper", SFML.Window.Styles.None); - _wallpaperRenderWindow.SetVisible(false); + _wallpaperRenderWindow.MaxFps = 30; + var handle = _wallpaperRenderWindow.SystemHandle; var style = User32.GetWindowLong(handle, User32.GWL_STYLE) | User32.WS_POPUP; - var exStyle = User32.GetWindowLong(handle, User32.GWL_EXSTYLE) | User32.WS_EX_LAYERED | User32.WS_EX_TOOLWINDOW; + var exStyle = User32.GetWindowLong(handle, User32.GWL_EXSTYLE) | User32.WS_EX_TOOLWINDOW; User32.SetWindowLong(handle, User32.GWL_STYLE, style); User32.SetWindowLong(handle, User32.GWL_EXSTYLE, exStyle); - User32.SetLayeredWindowAttributes(handle, 0, byte.MaxValue, User32.LWA_ALPHA); DataContext = _vm = new(_renderPanel, _wallpaperRenderWindow); @@ -153,9 +154,8 @@ public partial class MainWindow : Window private void MainWindow_SourceInitialized(object? sender, EventArgs e) { - var hwnd = new WindowInteropHelper(this).Handle; - Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText); - Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region); + this.SetWindowTextColor(AppResource.Color_PrimaryText); + this.SetWindowCaptionColor(AppResource.Color_Region); } private void MainWindow_Loaded(object sender, RoutedEventArgs e) diff --git a/SpineViewer/Views/PreferenceDialog.xaml.cs b/SpineViewer/Views/PreferenceDialog.xaml.cs index 849f47b..27f7aff 100644 --- a/SpineViewer/Views/PreferenceDialog.xaml.cs +++ b/SpineViewer/Views/PreferenceDialog.xaml.cs @@ -1,4 +1,4 @@ -using SpineViewer.Natives; +using SpineViewer.Extensions; using SpineViewer.Resources; using SpineViewer.Services; using SpineViewer.ViewModels.Exporters; @@ -16,6 +16,7 @@ using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; +using Win32Natives; namespace SpineViewer.Views { @@ -32,9 +33,8 @@ namespace SpineViewer.Views private void PreferenceDialog_SourceInitialized(object? sender, EventArgs e) { - var hwnd = new WindowInteropHelper(this).Handle; - Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText); - Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region); + this.SetWindowTextColor(AppResource.Color_PrimaryText); + this.SetWindowCaptionColor(AppResource.Color_Region); } private void ButtonOK_Click(object sender, RoutedEventArgs e) diff --git a/SpineViewer/Views/ProgressDialog.xaml.cs b/SpineViewer/Views/ProgressDialog.xaml.cs index fde5c03..d59f955 100644 --- a/SpineViewer/Views/ProgressDialog.xaml.cs +++ b/SpineViewer/Views/ProgressDialog.xaml.cs @@ -1,4 +1,4 @@ -using SpineViewer.Natives; +using SpineViewer.Extensions; using SpineViewer.Resources; using SpineViewer.ViewModels; using System; @@ -16,6 +16,7 @@ using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; +using Win32Natives; namespace SpineViewer.Views { @@ -33,9 +34,8 @@ namespace SpineViewer.Views private void ProgressDialog_SourceInitialized(object? sender, EventArgs e) { - var hwnd = new WindowInteropHelper(this).Handle; - Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText); - Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region); + this.SetWindowTextColor(AppResource.Color_PrimaryText); + this.SetWindowCaptionColor(AppResource.Color_Region); } private void ProgressWindow_Loaded(object sender, RoutedEventArgs e) diff --git a/SpineViewer/Natives/Dwmapi.cs b/Win32Natives/Dwmapi.cs similarity index 81% rename from SpineViewer/Natives/Dwmapi.cs rename to Win32Natives/Dwmapi.cs index 29fe400..2776186 100644 --- a/SpineViewer/Natives/Dwmapi.cs +++ b/Win32Natives/Dwmapi.cs @@ -4,9 +4,8 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; -using System.Windows.Media; -namespace SpineViewer.Natives +namespace Win32Natives { /// /// dwmapi.dll 包装类 @@ -24,15 +23,15 @@ namespace SpineViewer.Natives [DllImport("dwmapi.dll")] private static extern int DwmSetWindowAttribute(IntPtr hwnd, uint dwAttribute, ref uint pvAttribute, int cbAttribute); - public static bool SetWindowCaptionColor(IntPtr hwnd, Color color) + public static bool SetWindowCaptionColor(IntPtr hwnd, byte r, byte g, byte b) { - int c = color.R | (color.G << 8) | (color.B << 16); + int c = r | (g << 8) | (b << 16); return 0 == DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, ref c, sizeof(uint)); } - public static bool SetWindowTextColor(IntPtr hwnd, Color color) + public static bool SetWindowTextColor(IntPtr hwnd, byte r, byte g, byte b) { - int c = color.R | (color.G << 8) | (color.B << 16); + int c = r | (g << 8) | (b << 16); return 0 == DwmSetWindowAttribute(hwnd, DWMWA_TEXT_COLOR, ref c, sizeof(uint)); } diff --git a/SpineViewer/Natives/Gdi32.cs b/Win32Natives/Gdi32.cs similarity index 96% rename from SpineViewer/Natives/Gdi32.cs rename to Win32Natives/Gdi32.cs index 5845cf9..fb3e77e 100644 --- a/SpineViewer/Natives/Gdi32.cs +++ b/Win32Natives/Gdi32.cs @@ -7,7 +7,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows; -namespace SpineViewer.Natives +namespace Win32Natives { /// /// gdi32.dll 包装类 diff --git a/SpineViewer/Natives/Shell32.cs b/Win32Natives/Shell32.cs similarity index 96% rename from SpineViewer/Natives/Shell32.cs rename to Win32Natives/Shell32.cs index 1a08aa6..e6ac8ba 100644 --- a/SpineViewer/Natives/Shell32.cs +++ b/Win32Natives/Shell32.cs @@ -7,7 +7,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows; -namespace SpineViewer.Natives +namespace Win32Natives { /// /// shell32.dll 包装类 diff --git a/SpineViewer/Natives/User32.cs b/Win32Natives/User32.cs similarity index 99% rename from SpineViewer/Natives/User32.cs rename to Win32Natives/User32.cs index 4702bd6..1dd4a09 100644 --- a/SpineViewer/Natives/User32.cs +++ b/Win32Natives/User32.cs @@ -7,7 +7,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows; -namespace SpineViewer.Natives +namespace Win32Natives { /// /// user32.dll 包装类 diff --git a/Win32Natives/Win32Natives.csproj b/Win32Natives/Win32Natives.csproj new file mode 100644 index 0000000..d706d22 --- /dev/null +++ b/Win32Natives/Win32Natives.csproj @@ -0,0 +1,14 @@ + + + + enable + enable + x64 + x64 + net8.0-windows + $(SolutionDir)out + false + 0.0.1 + + + From 874404e3d3995a44144bdc5bd4c98b9226aaab95 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sat, 8 Nov 2025 19:44:15 +0800 Subject: [PATCH 11/16] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E5=B8=A7=E7=8E=87=E7=9A=84=E9=A6=96=E9=80=89=E9=A1=B9=EF=BC=8C?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E7=94=A8=E6=88=B7=E7=8A=B6=E6=80=81=E4=B8=AD?= =?UTF-8?q?=E6=9C=80=E5=A4=A7=E5=B8=A7=E7=8E=87=E7=9A=84=E8=AE=B0=E5=BF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpineViewer/Models/PreferenceModel.cs | 28 +++++--- SpineViewer/Models/UserStateModel.cs | 1 - SpineViewer/Resources/Strings/en.xaml | 2 + SpineViewer/Resources/Strings/ja.xaml | 2 + SpineViewer/Resources/Strings/zh.xaml | 2 + .../MainWindow/PreferenceViewModel.cs | 64 +++++++++++------ .../MainWindow/SFMLRendererViewModel.cs | 8 ++- SpineViewer/Views/MainWindow.xaml | 10 --- SpineViewer/Views/MainWindow.xaml.cs | 3 - SpineViewer/Views/PreferenceDialog.xaml | 68 ++++++++++++------- 10 files changed, 120 insertions(+), 68 deletions(-) diff --git a/SpineViewer/Models/PreferenceModel.cs b/SpineViewer/Models/PreferenceModel.cs index 1575935..7385520 100644 --- a/SpineViewer/Models/PreferenceModel.cs +++ b/SpineViewer/Models/PreferenceModel.cs @@ -73,6 +73,22 @@ namespace SpineViewer.Models #endregion + #region 预览画面首选项 + + [ObservableProperty] + private bool _renderSelectedOnly; + + [ObservableProperty] + private HitTestLevel _hitTestLevel; + + [ObservableProperty] + private bool _logHitSlots; + + [ObservableProperty] + private uint _maxFps = 30; + + #endregion + #region 程序选项 public RelayCommand Cmd_SelectAutoRunWorkspaceConfigPath => _cmd_SelectAutoRunWorkspaceConfigPath ??= new(() => @@ -89,18 +105,12 @@ namespace SpineViewer.Models [ObservableProperty] private AppSkin _appSkin; - [ObservableProperty] - private bool _renderSelectedOnly; - - [ObservableProperty] - private HitTestLevel _hitTestLevel; - - [ObservableProperty] - private bool _logHitSlots; - [ObservableProperty] private bool _wallpaperView; + [ObservableProperty] + private uint _wallpaperMaxFps = 30; + [ObservableProperty] private bool _closeToTray; diff --git a/SpineViewer/Models/UserStateModel.cs b/SpineViewer/Models/UserStateModel.cs index 8a0d73f..6ed5643 100644 --- a/SpineViewer/Models/UserStateModel.cs +++ b/SpineViewer/Models/UserStateModel.cs @@ -43,7 +43,6 @@ namespace SpineViewer.Models public uint ResolutionX { get; set; } = 1500; public uint ResolutionY { get; set; } = 1000; - public uint MaxFps { get; set; } = 30; public float Speed { get; set; } = 1f; public bool ShowAxis { get; set; } = true; public Color BackgroundColor { get; set; } = Color.FromRgb(105, 105, 105); diff --git a/SpineViewer/Resources/Strings/en.xaml b/SpineViewer/Resources/Strings/en.xaml index 5f979db..e22e54a 100644 --- a/SpineViewer/Resources/Strings/en.xaml +++ b/SpineViewer/Resources/Strings/en.xaml @@ -123,6 +123,8 @@ Maximum frame rate of the preview. Set to 0 for no limit. Playback Speed Wallpaper View + Max FPS of Wallpaper View + Maximum frame rate of the wallpaper view. Set to 0 for no limit. Render Selected Only Hit Test Accuracy Level Output Hit Test Slot Names diff --git a/SpineViewer/Resources/Strings/ja.xaml b/SpineViewer/Resources/Strings/ja.xaml index 9d607b7..0aa2bdb 100644 --- a/SpineViewer/Resources/Strings/ja.xaml +++ b/SpineViewer/Resources/Strings/ja.xaml @@ -123,6 +123,8 @@ プレビュー画面の最大フレームレート。0 に設定すると制限なし。 再生速度 壁紙表示 + 壁紙ビューの最大FPS + 壁紙ビューの最大フレームレート。0に設定すると制限がなし。 選択のみレンダリング ヒットテスト精度レベル ヒットテスト結果のスロット名を出力 diff --git a/SpineViewer/Resources/Strings/zh.xaml b/SpineViewer/Resources/Strings/zh.xaml index 12959e2..d17b08f 100644 --- a/SpineViewer/Resources/Strings/zh.xaml +++ b/SpineViewer/Resources/Strings/zh.xaml @@ -123,6 +123,8 @@ 预览画面的最大帧率,设置为 0 时则无帧率限制 播放速度 桌面投影 + 桌面投影最大帧率 + 桌面投影的最大帧率,设置为 0 时则无帧率限制 仅渲染选中 命中检测准确度等级 输出命中检测结果的插槽名称 diff --git a/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs b/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs index a7efe9c..989e186 100644 --- a/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs @@ -107,12 +107,15 @@ namespace SpineViewer.ViewModels.MainWindow DebugPoints = DebugPoints, DebugClippings = DebugClippings, - AppLanguage = AppLanguage, - AppSkin = AppSkin, RenderSelectedOnly = RenderSelectedOnly, HitTestLevel = HitTestLevel, LogHitSlots = LogHitSlots, + MaxFps = MaxFps, + + AppLanguage = AppLanguage, + AppSkin = AppSkin, WallpaperView = WallpaperView, + WallpaperMaxFps = WallpaperMaxFps, CloseToTray = CloseToTray, AutoRun = AutoRun, AutoRunWorkspaceConfigPath = AutoRunWorkspaceConfigPath, @@ -139,12 +142,15 @@ namespace SpineViewer.ViewModels.MainWindow DebugPoints = value.DebugPoints; DebugClippings = value.DebugClippings; - AppLanguage = value.AppLanguage; - AppSkin = value.AppSkin; RenderSelectedOnly = value.RenderSelectedOnly; HitTestLevel = value.HitTestLevel; LogHitSlots = value.LogHitSlots; + MaxFps = value.MaxFps; + + AppLanguage = value.AppLanguage; + AppSkin = value.AppSkin; WallpaperView = value.WallpaperView; + WallpaperMaxFps = value.WallpaperMaxFps; CloseToTray = value.CloseToTray; AutoRun = value.AutoRun; AutoRunWorkspaceConfigPath = value.AutoRunWorkspaceConfigPath; @@ -250,26 +256,10 @@ namespace SpineViewer.ViewModels.MainWindow #endregion - #region 程序选项 - - public static ImmutableArray AppLanguageOptions { get; } = Enum.GetValues().ToImmutableArray(); - - public static ImmutableArray AppSkinOptions { get; } = Enum.GetValues().ToImmutableArray(); + #region 预览画面首选项 public static ImmutableArray HitTestLevelOptions { get; } = Enum.GetValues().ToImmutableArray(); - public AppLanguage AppLanguage - { - get => ((App)App.Current).Language; - set => SetProperty(((App)App.Current).Language, value, v => ((App)App.Current).Language = v); - } - - public AppSkin AppSkin - { - get => ((App)App.Current).Skin; - set => SetProperty(((App)App.Current).Skin, value, v => ((App)App.Current).Skin = v); - } - public bool RenderSelectedOnly { get => _vmMain.SFMLRendererViewModel.RenderSelectedOnly; @@ -288,12 +278,44 @@ namespace SpineViewer.ViewModels.MainWindow set => SetProperty(SpineExtension.LogHitSlots, value, v => SpineExtension.LogHitSlots = v); } + public uint MaxFps + { + get => _vmMain.SFMLRendererViewModel.MaxFps; + set => SetProperty(_vmMain.SFMLRendererViewModel.MaxFps, value, v => _vmMain.SFMLRendererViewModel.MaxFps = v); + } + + #endregion + + #region 程序选项 + + public static ImmutableArray AppLanguageOptions { get; } = Enum.GetValues().ToImmutableArray(); + + public static ImmutableArray AppSkinOptions { get; } = Enum.GetValues().ToImmutableArray(); + + public AppLanguage AppLanguage + { + get => ((App)App.Current).Language; + set => SetProperty(((App)App.Current).Language, value, v => ((App)App.Current).Language = v); + } + + public AppSkin AppSkin + { + get => ((App)App.Current).Skin; + set => SetProperty(((App)App.Current).Skin, value, v => ((App)App.Current).Skin = v); + } + public bool WallpaperView { get => _vmMain.SFMLRendererViewModel.WallpaperView; set => SetProperty(_vmMain.SFMLRendererViewModel.WallpaperView, value, v => _vmMain.SFMLRendererViewModel.WallpaperView = v); } + public uint WallpaperMaxFps + { + get => _vmMain.SFMLRendererViewModel.WallpaperMaxFps; + set => SetProperty(_vmMain.SFMLRendererViewModel.WallpaperMaxFps, value, v => _vmMain.SFMLRendererViewModel.WallpaperMaxFps = v); + } + public bool CloseToTray { get => _vmMain.CloseToTray; diff --git a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs index cd0f664..ea396b1 100644 --- a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs @@ -160,7 +160,13 @@ namespace SpineViewer.ViewModels.MainWindow public uint MaxFps { get => _renderer.MaxFps; - set => SetProperty(_renderer.MaxFps, value, v => _renderer.MaxFps = _wallpaperRenderer.MaxFps = value); + set => SetProperty(_renderer.MaxFps, value, v => _renderer.MaxFps = value); + } + + public uint WallpaperMaxFps + { + get => _wallpaperRenderer.MaxFps; + set => SetProperty(_wallpaperRenderer.MaxFps, value, v => _wallpaperRenderer.MaxFps = value); } public float RealTimeFps => _realTimeFps; diff --git a/SpineViewer/Views/MainWindow.xaml b/SpineViewer/Views/MainWindow.xaml index 7e46fa2..8f277bf 100644 --- a/SpineViewer/Views/MainWindow.xaml +++ b/SpineViewer/Views/MainWindow.xaml @@ -793,16 +793,6 @@ - - - - - - - - diff --git a/SpineViewer/Views/MainWindow.xaml.cs b/SpineViewer/Views/MainWindow.xaml.cs index cf59900..aa60aff 100644 --- a/SpineViewer/Views/MainWindow.xaml.cs +++ b/SpineViewer/Views/MainWindow.xaml.cs @@ -274,7 +274,6 @@ public partial class MainWindow : Window _vm.ExplorerListViewModel.CurrentDirectory = m.ExploringDirectory; _vm.SFMLRendererViewModel.SetResolution(m.ResolutionX, m.ResolutionY); - _vm.SFMLRendererViewModel.MaxFps = m.MaxFps; _vm.SFMLRendererViewModel.Speed = m.Speed; _vm.SFMLRendererViewModel.ShowAxis = m.ShowAxis; _vm.SFMLRendererViewModel.BackgroundColor = m.BackgroundColor; @@ -310,7 +309,6 @@ public partial class MainWindow : Window ResolutionX = _vm.SFMLRendererViewModel.ResolutionX, ResolutionY = _vm.SFMLRendererViewModel.ResolutionY, - MaxFps = _vm.SFMLRendererViewModel.MaxFps, Speed = _vm.SFMLRendererViewModel.Speed, ShowAxis = _vm.SFMLRendererViewModel.ShowAxis, BackgroundColor = _vm.SFMLRendererViewModel.BackgroundColor, @@ -400,7 +398,6 @@ public partial class MainWindow : Window { case nameof(SFMLRendererViewModel.ResolutionX): case nameof(SFMLRendererViewModel.ResolutionY): - case nameof(SFMLRendererViewModel.MaxFps): case nameof(SFMLRendererViewModel.Speed): case nameof(SFMLRendererViewModel.ShowAxis): case nameof(SFMLRendererViewModel.BackgroundColor): diff --git a/SpineViewer/Views/PreferenceDialog.xaml b/SpineViewer/Views/PreferenceDialog.xaml index f962604..9bb520b 100644 --- a/SpineViewer/Views/PreferenceDialog.xaml +++ b/SpineViewer/Views/PreferenceDialog.xaml @@ -195,30 +195,8 @@ - + - - - - - - - - - - - - - - @@ -248,6 +226,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + @@ -257,6 +270,15 @@ + + + + + + + From e96db328fa163b604edc35f09628536ae6910a9e Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sat, 8 Nov 2025 23:05:08 +0800 Subject: [PATCH 12/16] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=A1=8C=E9=9D=A2?= =?UTF-8?q?=E6=8A=95=E5=BD=B1=E5=B8=A7=E7=8E=87=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpineViewer/Models/WorkspaceModel.cs | 2 -- SpineViewer/Resources/Strings/en.xaml | 2 +- SpineViewer/Resources/Strings/ja.xaml | 2 +- SpineViewer/Resources/Strings/zh.xaml | 2 +- .../MainWindow/SFMLRendererViewModel.cs | 25 ++++++++++++++++--- SpineViewer/Views/MainWindow.xaml | 1 + 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/SpineViewer/Models/WorkspaceModel.cs b/SpineViewer/Models/WorkspaceModel.cs index a608cbb..7392d86 100644 --- a/SpineViewer/Models/WorkspaceModel.cs +++ b/SpineViewer/Models/WorkspaceModel.cs @@ -34,8 +34,6 @@ namespace SpineViewer.Models public bool FlipY { get; set; } = true; - public uint MaxFps { get; set; } = 30; - public float Speed { get; set; } = 1f; public bool ShowAxis { get; set; } = true; diff --git a/SpineViewer/Resources/Strings/en.xaml b/SpineViewer/Resources/Strings/en.xaml index e22e54a..d584489 100644 --- a/SpineViewer/Resources/Strings/en.xaml +++ b/SpineViewer/Resources/Strings/en.xaml @@ -143,7 +143,7 @@ Window/Fullscreen; F11 - Real-time FPS: {0:F1} + Real-time FPS: {0:F1}/{1:F1} OK diff --git a/SpineViewer/Resources/Strings/ja.xaml b/SpineViewer/Resources/Strings/ja.xaml index 0aa2bdb..37fb083 100644 --- a/SpineViewer/Resources/Strings/ja.xaml +++ b/SpineViewer/Resources/Strings/ja.xaml @@ -143,7 +143,7 @@ ウィンドウ/フルスクリーン; F11 - リアルタイムFPS:{0:F1} + リアルタイムFPS:{0:F1}/{1:F1} OK diff --git a/SpineViewer/Resources/Strings/zh.xaml b/SpineViewer/Resources/Strings/zh.xaml index d17b08f..99c1523 100644 --- a/SpineViewer/Resources/Strings/zh.xaml +++ b/SpineViewer/Resources/Strings/zh.xaml @@ -143,7 +143,7 @@ 窗口/全屏; F11 - 实时帧率:{0:F1} + 实时帧率:{0:F1}/{1:F1} 确认 diff --git a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs index ea396b1..9a5ea91 100644 --- a/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/SFMLRendererViewModel.cs @@ -175,6 +175,12 @@ namespace SpineViewer.ViewModels.MainWindow private float _accumFpsTime; private int _accumFpsCount; + public float WallpaperRealTimeFps => _wallpaperRealTimeFps; + private float _wallpaperRealTimeFps; + + private int _accumWallpaperFpsCount; + private readonly object _accumWallpaperFpsCountLock = new(); + public float Speed { get => _speed; @@ -516,14 +522,21 @@ namespace SpineViewer.ViewModels.MainWindow private void UpdateLogicFrame(float delta) { // 计算实时帧率, 1 秒刷新一次 - _accumFpsCount++; _accumFpsTime += delta; if (_accumFpsTime > 1f) { _realTimeFps = _accumFpsCount / _accumFpsTime; - _accumFpsTime = 0f; _accumFpsCount = 0; + + lock (_accumWallpaperFpsCountLock) + { + _wallpaperRealTimeFps = _accumWallpaperFpsCount / _accumFpsTime; + _accumWallpaperFpsCount = 0; + } + + _accumFpsTime = 0f; OnPropertyChanged(nameof(RealTimeFps)); + OnPropertyChanged(nameof(WallpaperRealTimeFps)); } // 停止更新的时候只是时间不前进, 但是坐标变换还是要更新, 否则无法移动对象 @@ -634,6 +647,9 @@ namespace SpineViewer.ViewModels.MainWindow // 显示内容 _renderer.Display(); + + // 帧数加一 + _accumFpsCount++; } private void WallpaperRenderTask() @@ -679,6 +695,9 @@ namespace SpineViewer.ViewModels.MainWindow // 显示渲染 _wallpaperRenderer.Display(); + + // 帧数加一 + lock (_accumWallpaperFpsCountLock) _accumWallpaperFpsCount++; } } catch (Exception ex) @@ -707,7 +726,6 @@ namespace SpineViewer.ViewModels.MainWindow Rotation = Rotation, FlipX = FlipX, FlipY = FlipY, - MaxFps = MaxFps, Speed = Speed, ShowAxis = ShowAxis, BackgroundColor = BackgroundColor, @@ -724,7 +742,6 @@ namespace SpineViewer.ViewModels.MainWindow Rotation = value.Rotation; FlipX = value.FlipX; FlipY = value.FlipY; - MaxFps = value.MaxFps; Speed = value.Speed; ShowAxis = value.ShowAxis; BackgroundColor = value.BackgroundColor; diff --git a/SpineViewer/Views/MainWindow.xaml b/SpineViewer/Views/MainWindow.xaml index 8f277bf..0a2fcfa 100644 --- a/SpineViewer/Views/MainWindow.xaml +++ b/SpineViewer/Views/MainWindow.xaml @@ -1052,6 +1052,7 @@ + From 2b53e0b60b69a83fe58b832c79550d52f3b9dbf2 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sun, 9 Nov 2025 00:27:01 +0800 Subject: [PATCH 13/16] =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SFMLRenderer/SFMLRenderWindow.cs | 9 +++++++++ SFMLRenderer/SFMLRenderer.csproj | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/SFMLRenderer/SFMLRenderWindow.cs b/SFMLRenderer/SFMLRenderWindow.cs index ce31211..41f8327 100644 --- a/SFMLRenderer/SFMLRenderWindow.cs +++ b/SFMLRenderer/SFMLRenderWindow.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Threading; +using Win32Natives; namespace SFMLRenderer { @@ -19,6 +20,14 @@ namespace SFMLRenderer SetActive(false); _timer.Tick += (s, e) => DispatchEvents(); _timer.Start(); + + SetVisible(false); + + var handle = SystemHandle; + var exStyle = User32.GetWindowLong(handle, User32.GWL_EXSTYLE) | User32.WS_EX_LAYERED; + User32.SetWindowLong(handle, User32.GWL_EXSTYLE, exStyle); + User32.SetLayeredWindowAttributes(handle, 0, byte.MaxValue, User32.LWA_ALPHA); + RendererCreated?.Invoke(this, EventArgs.Empty); } diff --git a/SFMLRenderer/SFMLRenderer.csproj b/SFMLRenderer/SFMLRenderer.csproj index 9d047ed..f05e384 100644 --- a/SFMLRenderer/SFMLRenderer.csproj +++ b/SFMLRenderer/SFMLRenderer.csproj @@ -20,4 +20,8 @@ + + + + From 6f2eb504ab64ce3831d52b780329614ee11d0bb4 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sun, 9 Nov 2025 12:29:41 +0800 Subject: [PATCH 14/16] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=B5=8C=E5=85=A5?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpineViewer/Views/MainWindow.xaml.cs | 18 +++++++++++++----- Win32Natives/User32.cs | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/SpineViewer/Views/MainWindow.xaml.cs b/SpineViewer/Views/MainWindow.xaml.cs index aa60aff..6844fbc 100644 --- a/SpineViewer/Views/MainWindow.xaml.cs +++ b/SpineViewer/Views/MainWindow.xaml.cs @@ -449,17 +449,25 @@ public partial class MainWindow : Window _logger.Error("Failed to enable wallpaper view, WorkerW not found"); return; } - var handle = wnd.SystemHandle; User32.GetPrimaryScreenResolution(out var sw, out var sh); + _vm.SFMLRendererViewModel.SetResolution(sw, sh); - User32.SetParent(handle, workerw); + var handle = wnd.SystemHandle; + + // 每次都进行设置, 确保会成为顶层子窗口 + var lastParent = User32.SetParent(handle, workerw); + Debug.WriteLine($"0x{lastParent:x8} = SetParent(0x{handle:x8}, 0x{workerw:x8})"); User32.SetLayeredWindowAttributes(handle, 0, byte.MaxValue, User32.LWA_ALPHA); - _vm.SFMLRendererViewModel.SetResolution(sw, sh); + // XXX: 每次新设置成桌面子窗口之后, 要确保窗口 Size 发生一次变化来触发 SFML 内部的渲染视图更新 + var ssize = new SFML.System.Vector2u(sw, sh); + if (lastParent != workerw && ssize == wnd.Size) + { + wnd.Size = new(sw + 1, sh); + } wnd.Position = new(0, 0); - wnd.Size = new(sw + 1, sh); - wnd.Size = new(sw, sh); + wnd.Size = ssize; wnd.SetVisible(true); } else diff --git a/Win32Natives/User32.cs b/Win32Natives/User32.cs index 1dd4a09..0d25a62 100644 --- a/Win32Natives/User32.cs +++ b/Win32Natives/User32.cs @@ -316,7 +316,7 @@ namespace Win32Natives workerw = FindWindowEx(progman, IntPtr.Zero, "WorkerW", null); } - Debug.WriteLine($"HWND(WorkerW): {workerw:x8}"); + Debug.WriteLine($"HWND(WorkerW): 0x{workerw:x8}"); return workerw; } From 608de7f2e844fdc6b4ce3dc5e6e4b15d7b7bc0aa Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sun, 9 Nov 2025 23:18:26 +0800 Subject: [PATCH 15/16] update to v0.16.12 --- SpineViewer/SpineViewer.csproj | 2 +- SpineViewerCLI/SpineViewerCLI.csproj | 2 +- Win32Natives/Win32Natives.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SpineViewer/SpineViewer.csproj b/SpineViewer/SpineViewer.csproj index b5ff95c..dac2fcd 100644 --- a/SpineViewer/SpineViewer.csproj +++ b/SpineViewer/SpineViewer.csproj @@ -8,7 +8,7 @@ net8.0-windows $(SolutionDir)out false - 0.16.11 + 0.16.12 WinExe true diff --git a/SpineViewerCLI/SpineViewerCLI.csproj b/SpineViewerCLI/SpineViewerCLI.csproj index 680952a..837c393 100644 --- a/SpineViewerCLI/SpineViewerCLI.csproj +++ b/SpineViewerCLI/SpineViewerCLI.csproj @@ -8,7 +8,7 @@ net8.0 $(SolutionDir)out false - 0.16.11 + 0.16.12 Exe diff --git a/Win32Natives/Win32Natives.csproj b/Win32Natives/Win32Natives.csproj index d706d22..1ae1ffe 100644 --- a/Win32Natives/Win32Natives.csproj +++ b/Win32Natives/Win32Natives.csproj @@ -8,7 +8,7 @@ net8.0-windows $(SolutionDir)out false - 0.0.1 + 0.16.0 From 83d054382c247a25fd14529be09e11b7a3ed9c01 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sun, 9 Nov 2025 23:22:11 +0800 Subject: [PATCH 16/16] update changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d0bdd2..658d416 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # CHANGELOG +## v0.16.12 + +- 修复 label 控件文字显示问题 +- 增强报错日志输出 +- 增加实时帧率显示 +- 首选项增加预览画面和投影最大帧率设置,移除用户状态和工作区帧率记忆 +- 优化某些性能 + ## v0.16.11 - 增加 shift 切换缩放倍数