Compare commits

..

8 Commits

Author SHA1 Message Date
ww-rm
8e1f586d4f Merge pull request #86 from ww-rm/dev/wpf
fix bug
2025-08-20 22:44:47 +08:00
ww-rm
ad190d8952 Merge pull request #85 from ww-rm/dev/wpf
v0.15.11
2025-08-20 22:36:14 +08:00
ww-rm
40bde84648 Merge pull request #81 from ww-rm/dev/wpf
v0.15.10
2025-08-18 18:54:13 +08:00
ww-rm
a697ccc923 Merge pull request #80 from ww-rm/dev/wpf 2025-08-18 01:26:40 +08:00
ww-rm
65508782c6 Merge pull request #77 from ww-rm/dev/wpf
v0.15.8
2025-08-01 00:03:42 +08:00
ww-rm
7bc82ab318 Merge pull request #75 from ww-rm/dev/wpf
fix bug
2025-07-26 23:06:01 +08:00
ww-rm
eca59dc67b Merge pull request #74 from ww-rm/dev/wpf
v0.15.7
2025-07-26 23:01:21 +08:00
ww-rm
497103bdb6 Merge pull request #69 from ww-rm/dev/wpf 2025-07-25 14:00:15 +08:00
280 changed files with 3317 additions and 8594 deletions

View File

@@ -1,18 +0,0 @@
---
name: 问题报告/Bug report
about: 报告可能的程序错误/Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
## 问题描述/Describe the bug
清晰完整的描述问题是什么以及如何发生的。/A clear and concise description of what the bug is.
## 复现方式(可选)/To Reproduce (Optional)
## 截图(可选)/Screenshots (Optional)**
如果有必要,提供报错时的有关截图。/If applicable, add screenshots to help explain your problem.
## 附件(可选)/Attachments (Optional)
请将会**出现问题的文件**以及**日志文件**打包成一个 ZIP 后作为附件贴在 issue 内,日志文件位于程序目录下的 `logs` 文件夹内。/Please compress the problematic files and the log files into a single ZIP archive and attach it to this issue. The log files are located in the `logs` folder under the program directory.

View File

@@ -11,10 +11,6 @@ jobs:
build-release: build-release:
if: ${{ github.event.pull_request.merged == true }} if: ${{ github.event.pull_request.merged == true }}
runs-on: windows-latest runs-on: windows-latest
outputs:
version: ${{ steps.extract_version.outputs.version }}
upload_url: ${{ steps.create_release.outputs.upload_url }}
env: env:
PROJECT_NAME: SpineViewer PROJECT_NAME: SpineViewer
PROJ_CLI_NAME: SpineViewerCLI PROJ_CLI_NAME: SpineViewerCLI
@@ -31,15 +27,21 @@ jobs:
dotnet-version: "8.0.x" dotnet-version: "8.0.x"
- name: Extract version from csproj - name: Extract version from csproj
id: extract_version
shell: pwsh shell: pwsh
run: | run: |
[xml]$proj = Get-Content "$env:PROJECT_NAME\$env:PROJECT_NAME.csproj" [xml]$proj = Get-Content "$env:PROJECT_NAME\$env:PROJECT_NAME.csproj"
$VERSION_NUM = $proj.Project.PropertyGroup.Version $VERSION_NUM = $proj.Project.PropertyGroup.Version
$VERSION_TAG = "v$VERSION_NUM".Trim() $VERSION_TAG = "v$VERSION_NUM".Trim()
echo "Version tag found: $VERSION_TAG" "VERSION=$VERSION_TAG" >> $env:GITHUB_ENV
echo "version=$VERSION_TAG" >> $env:GITHUB_OUTPUT
echo "VERSION=$VERSION_TAG" >> $env:GITHUB_ENV - name: Check Version Tag
shell: pwsh
run: |
if (-not $env:VERSION) {
Write-Error "Version tag not found in csproj file."
exit 1
}
Write-Host "Version tag found: $env:VERSION"
- name: Tag merge commit - name: Tag merge commit
shell: pwsh shell: pwsh
@@ -61,11 +63,19 @@ jobs:
dotnet publish "$env:PROJECT_NAME\$env:PROJECT_NAME.csproj" -c Release -r win-x64 --sc true -o "publish\$env:PROJECT_NAME-$env:VERSION-SelfContained" dotnet publish "$env:PROJECT_NAME\$env:PROJECT_NAME.csproj" -c Release -r win-x64 --sc true -o "publish\$env:PROJECT_NAME-$env:VERSION-SelfContained"
dotnet publish "$env:PROJ_CLI_NAME\$env:PROJ_CLI_NAME.csproj" -c Release -r win-x64 --sc true -o "publish\$env:PROJECT_NAME-$env:VERSION-SelfContained" dotnet publish "$env:PROJ_CLI_NAME\$env:PROJ_CLI_NAME.csproj" -c Release -r win-x64 --sc true -o "publish\$env:PROJECT_NAME-$env:VERSION-SelfContained"
- name: Compress Windows builds - name: Create release directory
shell: pwsh shell: pwsh
run: | run: |
New-Item -ItemType Directory -Path release -Force | Out-Null New-Item -ItemType Directory -Path release -Force | Out-Null
- name: Compress FrameworkDependent version
shell: pwsh
run: |
Compress-Archive -Path "publish\$env:PROJECT_NAME-$env:VERSION\*" -DestinationPath "release\$env:PROJECT_NAME-$env:VERSION.zip" -Force Compress-Archive -Path "publish\$env:PROJECT_NAME-$env:VERSION\*" -DestinationPath "release\$env:PROJECT_NAME-$env:VERSION.zip" -Force
- name: Compress SelfContained version
shell: pwsh
run: |
Compress-Archive -Path "publish\$env:PROJECT_NAME-$env:VERSION-SelfContained\*" -DestinationPath "release\$env:PROJECT_NAME-$env:VERSION-SelfContained.zip" -Force Compress-Archive -Path "publish\$env:PROJECT_NAME-$env:VERSION-SelfContained\*" -DestinationPath "release\$env:PROJECT_NAME-$env:VERSION-SelfContained.zip" -Force
- name: Create GitHub Release - name: Create GitHub Release
@@ -79,7 +89,7 @@ jobs:
draft: false draft: false
prerelease: false prerelease: false
- name: Upload Windows FrameworkDependent zip - name: Upload FrameworkDependent zip
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -89,7 +99,7 @@ jobs:
asset_name: ${{ env.PROJECT_NAME }}-${{ env.VERSION }}.zip asset_name: ${{ env.PROJECT_NAME }}-${{ env.VERSION }}.zip
asset_content_type: application/zip asset_content_type: application/zip
- name: Upload Windows SelfContained zip - name: Upload SelfContained zip
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -98,43 +108,3 @@ jobs:
asset_path: release/${{ env.PROJECT_NAME }}-${{ env.VERSION }}-SelfContained.zip asset_path: release/${{ env.PROJECT_NAME }}-${{ env.VERSION }}-SelfContained.zip
asset_name: ${{ env.PROJECT_NAME }}-${{ env.VERSION }}-SelfContained.zip asset_name: ${{ env.PROJECT_NAME }}-${{ env.VERSION }}-SelfContained.zip
asset_content_type: application/zip asset_content_type: application/zip
build-release-linux:
needs: build-release
if: ${{ github.event.pull_request.merged == true }}
runs-on: ubuntu-latest
env:
PROJ_CLI_NAME: SpineViewerCLI
VERSION: ${{ needs.build-release.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-tags: true
- name: Setup .NET SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: "8.0.x"
- name: Publish Linux SelfContained version
run: |
dotnet publish "$PROJ_CLI_NAME/$PROJ_CLI_NAME.csproj" -c Release -r linux-x64 --sc true -o "publish/${PROJ_CLI_NAME}-${VERSION}-Linux-SelfContained"
- name: Compress Linux build
run: |
mkdir -p release
cd publish
zip -r "../release/${PROJ_CLI_NAME}-${VERSION}-Linux-SelfContained.zip" "${PROJ_CLI_NAME}-${VERSION}-Linux-SelfContained"
- name: Upload Linux zip to GitHub Release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.build-release.outputs.upload_url }}
asset_path: release/${{ env.PROJ_CLI_NAME }}-${{ env.VERSION }}-Linux-SelfContained.zip
asset_name: ${{ env.PROJ_CLI_NAME }}-${{ env.VERSION }}-Linux-SelfContained.zip
asset_content_type: application/zip

2
.gitignore vendored
View File

@@ -396,5 +396,3 @@ FodyWeavers.xsd
# JetBrains Rider # JetBrains Rider
*.sln.iml *.sln.iml
launchSettings.json

View File

@@ -1,136 +1,5 @@
# CHANGELOG # CHANGELOG
## v0.16.12
- 修复 label 控件文字显示问题
- 增强报错日志输出
- 增加实时帧率显示
- 首选项增加预览画面和投影最大帧率设置,移除用户状态和工作区帧率记忆
- 优化某些性能
## v0.16.11
- 增加 shift 切换缩放倍数
- 改善后台性能
- 修复字体显示颜色问题
- 调整浏览目录参数保存至用户状态
- 调整浏览面板至最后
## v0.16.10
- 增加 Linux 平台 CLI 工具构建
## v0.16.9
- 重构 CLI 工具
## v0.16.8
- 去除首次的最小化提示弹框
- 窗口布局改变后实时保存
- 增加侧边栏图标和折叠功能
- 增加皮肤和插槽参数面板的全部启用/禁用菜单项
- 修改窗口默认大小
- 支持复制并应用单独的模型皮肤或插槽参数
## v0.16.7
- 修复空帧导致的包围盒计算错误
- 修复重复启动程序无法唤出界面的问题
## v0.16.6
- 修复控件尺寸为0时导致的画面缩放错误
## v0.16.5
- 修复对于无 size 行的旧 atlas 格式读取错误
- 修复托盘化之后无法联动显示窗口的问题
## v0.16.4
- 增加 apng 导出格式
- 增加颜色拾取器面板
- 增加程序皮肤(主题颜色)首选项
- 优化部分使用体验
## v0.16.3
- 修复加载工作区时的顺序错误
- 调整部分调试渲染的逻辑
- 完善命中检测逻辑
## v0.16.2
- 修复批量添加时的添加顺序错误
- 增加精确命中检测和插槽输出功能
- 部分代码重构
## v0.16.1
- 修复 3.4 版本存在的附件残留问题
## v0.16.0
- 增加最小化至托盘图标功能
- 调整部分参数项的顺序
- 增加开机自启和自启文件设置
- 切换桌面投影时自动设置预览分辨率为主屏幕分辨率
- 修复 3.4 版本下可能存在的附件残留问题
## v0.15.19
- 模型重载后选中最后一个重载模型
- 修复 3.4 版本可能的奇数顶点数组导致的越界崩溃问题
- 移除参数自动记录中的背景图片路径
- 增加测试性桌面投影功能
## v0.15.18
- 完善窗口日志颜色标记
- 修复预览图背景颜色为透明
- 修复面板高度首次还原错误
- 增加托盘图标
- 增加可选预览背景画面和填充模式
- 增强支持的纹理格式(例如 webp
## v0.15.17
- 修改图标配色
## v0.15.16
- 修改模型添加顺序, 每次向顶层添加
- 添加模型后自动选中最近添加的模型S
- 点击预览画面或者选中项发生变化时转移焦点至列表
- 增加移除全部菜单项
- 增加单例模式和命令行文件参数
- 增加文件关联设置
## v0.15.15
- 增加报错信息
- 导入后自动选中最后一项
## v0.15.14
- 将预览画面的首选项移动至上一次状态参数中
- 增加预览画面像素的自动保存和恢复
- 增加日志启动时的版本号输出
## v0.15.13
- 增加程序布局自动存储和还原
- 增加部分预览画面首选项
## v0.15.12
- 增加单个模型和单个轨道的时间因子
- 增加单个轨道的 Alpha 混合参数
- 调整轨道清除命令至右键菜单
- 设置默认标签页为模型
- 完善导入时的报错信息
## v0.15.11 ## v0.15.11
- 修复自定义导出中参数构造错误 - 修复自定义导出中参数构造错误

View File

@@ -1,17 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
<PlatformTarget>x64</PlatformTarget>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net8.0-windows</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath> <BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
<OutputPath>$(BaseOutputPath)\$(Configuration)\$(PlatformTarget)</OutputPath>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion> <IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<Version>0.16.0</Version> <Version>0.15.4</Version>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
</PropertyGroup> </PropertyGroup>

View File

@@ -1,53 +1,92 @@
using NLog; //
// Copyright (c) 2004-2011 Jaroslaw Kowalski <jaak@jkowalski.net>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of Jaroslaw Kowalski nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//
using NLog.Conditions; using NLog.Conditions;
using NLog.Config; using NLog.Config;
using NLog.Layouts; using NLog;
using System.ComponentModel;
using System.Windows; using System.Windows;
namespace NLog.Windows.Wpf namespace NLog.Windows.Wpf
{ {
[NLogConfigurationItem] [NLogConfigurationItem]
public class RichTextBoxRowColoringRule public class RichTextBoxRowColoringRule
{ {
static RichTextBoxRowColoringRule()
{
Default = new RichTextBoxRowColoringRule();
}
public RichTextBoxRowColoringRule()
: this(null, "Empty", "Empty", FontStyles.Normal, FontWeights.Normal)
{
}
public RichTextBoxRowColoringRule(string condition, string fontColor, string backColor, FontStyle fontStyle, FontWeight fontWeight)
{
Condition = condition;
FontColor = fontColor;
BackgroundColor = backColor;
Style = fontStyle;
Weight = fontWeight;
}
public RichTextBoxRowColoringRule(string condition, string fontColor, string backColor)
{
Condition = condition;
FontColor = fontColor;
BackgroundColor = backColor;
Style = FontStyles.Normal;
Weight = FontWeights.Normal;
}
public static RichTextBoxRowColoringRule Default { get; private set; } public static RichTextBoxRowColoringRule Default { get; private set; }
[RequiredParameter] [RequiredParameter]
public ConditionExpression Condition { get; set; } public ConditionExpression Condition { get; set; }
public Layout FontColor { get; set; } [DefaultValue("Empty")]
public Layout BackgroundColor { get; set; } public string FontColor { get; set; }
public FontStyle FontStyle { get; set; } [DefaultValue("Empty")]
public FontWeight FontWeight { get; set; } public string BackgroundColor { get; set; }
static RichTextBoxRowColoringRule() public FontStyle Style { get; set; }
{
RichTextBoxRowColoringRule.Default = new RichTextBoxRowColoringRule();
}
public RichTextBoxRowColoringRule() : this(null, "Empty", "Empty", FontStyles.Normal, FontWeights.Normal) { } public FontWeight Weight { get; set; }
public RichTextBoxRowColoringRule(string condition, string fontColor, string backColor)
{
this.Condition = (ConditionExpression)condition;
this.FontColor = Layout.FromString(fontColor);
this.BackgroundColor = Layout.FromString(backColor);
this.FontStyle = FontStyles.Normal;
this.FontWeight = FontWeights.Normal;
}
public RichTextBoxRowColoringRule(string condition, string fontColor, string backColor, FontStyle fontStyle, FontWeight fontWeight)
{
this.Condition = (ConditionExpression)condition;
this.FontColor = Layout.FromString(fontColor);
this.BackgroundColor = Layout.FromString(backColor);
this.FontStyle = fontStyle;
this.FontWeight = fontWeight;
}
public bool CheckCondition(LogEventInfo logEvent) public bool CheckCondition(LogEventInfo logEvent)
{ {
return true.Equals(this.Condition.Evaluate(logEvent)); return true.Equals(Condition.Evaluate(logEvent));
} }
} }
} }

View File

@@ -1,27 +1,34 @@
using NLog; using NLog.Config;
using NLog.Common; using NLog.Layouts;
using NLog.Config;
using NLog.Targets; using NLog.Targets;
using NLog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text;
using System.Windows; using System.Threading.Tasks;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Media; using System.Windows.Media;
using System.Windows;
namespace NLog.Windows.Wpf namespace NLog.Windows.Wpf
{ {
// TODO: 完善日志实现
[Target("RichTextBox")] [Target("RichTextBox")]
public sealed class RichTextBoxTarget : TargetWithLayout public sealed class RichTextBoxTarget : TargetWithLayout
{ {
public static ReadOnlyCollection<RichTextBoxRowColoringRule> DefaultRowColoringRules { get; } = CreateDefaultColoringRules(); private int lineCount;
private int _width = 500;
private int _height = 500;
private static readonly TypeConverter colorConverter = new ColorConverter();
private static ReadOnlyCollection<RichTextBoxRowColoringRule> CreateDefaultColoringRules() static RichTextBoxTarget()
{ {
return new List<RichTextBoxRowColoringRule>() var rules = new List<RichTextBoxRowColoringRule>()
{ {
new RichTextBoxRowColoringRule("level == LogLevel.Fatal", "White", "Red", FontStyles.Normal, FontWeights.Bold), new RichTextBoxRowColoringRule("level == LogLevel.Fatal", "White", "Red", FontStyles.Normal, FontWeights.Bold),
new RichTextBoxRowColoringRule("level == LogLevel.Error", "Red", "Empty", FontStyles.Italic, FontWeights.Bold), new RichTextBoxRowColoringRule("level == LogLevel.Error", "Red", "Empty", FontStyles.Italic, FontWeights.Bold),
@@ -29,253 +36,221 @@ namespace NLog.Windows.Wpf
new RichTextBoxRowColoringRule("level == LogLevel.Info", "Black", "Empty"), new RichTextBoxRowColoringRule("level == LogLevel.Info", "Black", "Empty"),
new RichTextBoxRowColoringRule("level == LogLevel.Debug", "Gray", "Empty"), new RichTextBoxRowColoringRule("level == LogLevel.Debug", "Gray", "Empty"),
new RichTextBoxRowColoringRule("level == LogLevel.Trace", "DarkGray", "Empty", FontStyles.Italic, FontWeights.Normal), new RichTextBoxRowColoringRule("level == LogLevel.Trace", "DarkGray", "Empty", FontStyles.Italic, FontWeights.Normal),
}.AsReadOnly(); };
DefaultRowColoringRules = rules.AsReadOnly();
} }
public RichTextBoxTarget() { } public RichTextBoxTarget()
{
WordColoringRules = new List<RichTextBoxWordColoringRule>();
RowColoringRules = new List<RichTextBoxRowColoringRule>();
ToolWindow = true;
}
private delegate void DelSendTheMessageToRichTextBox(string logMessage, RichTextBoxRowColoringRule rule);
private delegate void FormCloseDelegate();
public static ReadOnlyCollection<RichTextBoxRowColoringRule> DefaultRowColoringRules { get; private set; }
public string ControlName { get; set; } public string ControlName { get; set; }
public string WindowName { get; set; } public string FormName { get; set; }
[DefaultValue(false)]
public bool UseDefaultRowColoringRules { get; set; } public bool UseDefaultRowColoringRules { get; set; }
[ArrayParameter(typeof(RichTextBoxRowColoringRule), "row-coloring")]
public IList<RichTextBoxRowColoringRule> RowColoringRules { get; private set; }
[ArrayParameter(typeof(RichTextBoxWordColoringRule), "word-coloring")]
public IList<RichTextBoxWordColoringRule> WordColoringRules { get; private set; }
[DefaultValue(true)]
public bool ToolWindow { get; set; }
public bool ShowMinimized { get; set; }
public int Width
{
get { return _width; }
set { _width = value; }
}
public int Height
{
get { return _height; }
set { _height = value; }
}
public bool AutoScroll { get; set; } public bool AutoScroll { get; set; }
public int MaxLines { get; set; } public int MaxLines { get; set; }
[ArrayParameter(typeof(RichTextBoxRowColoringRule), "row-coloring")] internal Window TargetForm { get; set; }
public IList<RichTextBoxRowColoringRule> RowColoringRules { get; } = new List<RichTextBoxRowColoringRule>();
[ArrayParameter(typeof(RichTextBoxWordColoringRule), "word-coloring")] internal RichTextBox TargetRichTextBox { get; set; }
public IList<RichTextBoxWordColoringRule> WordColoringRules { get; } = new List<RichTextBoxWordColoringRule>();
[NLogConfigurationIgnoreProperty] internal bool CreatedForm { get; set; }
public Window TargetWindow { get; set; }
[NLogConfigurationIgnoreProperty]
public RichTextBox TargetRichTextBox { get; set; }
protected override void InitializeTarget() protected override void InitializeTarget()
{ {
base.InitializeTarget(); TargetRichTextBox = Application.Current.MainWindow.FindName(ControlName) as RichTextBox;
if (TargetRichTextBox != null)
return;
if (WindowName == null) if (TargetRichTextBox != null) return;
//this.TargetForm = FormHelper.CreateForm(this.FormName, this.Width, this.Height, false, this.ShowMinimized, this.ToolWindow);
//this.CreatedForm = true;
var openFormByName = Application.Current.Windows.Cast<Window>().FirstOrDefault(x => x.GetType().Name == FormName);
if (openFormByName != null)
{ {
HandleError("WindowName should be specified for {0}.{1}", GetType().Name, Name); TargetForm = openFormByName;
return; if (string.IsNullOrEmpty(ControlName))
{
// throw new NLogConfigurationException("Rich text box control name must be specified for " + GetType().Name + ".");
Trace.WriteLine("Rich text box control name must be specified for " + GetType().Name + ".");
}
CreatedForm = false;
TargetRichTextBox = TargetForm.FindName(ControlName) as RichTextBox;
if (TargetRichTextBox == null)
{
// throw new NLogConfigurationException("Rich text box control '" + ControlName + "' cannot be found on form '" + FormName + "'.");
Trace.WriteLine("Rich text box control '" + ControlName + "' cannot be found on form '" + FormName + "'.");
}
} }
if (string.IsNullOrEmpty(ControlName)) if (TargetRichTextBox == null)
{ {
HandleError("Rich text box control name must be specified for {0}.{1}", GetType().Name, Name); TargetForm = new Window
return; {
Name = FormName,
Width = Width,
Height = Height,
WindowStyle = ToolWindow ? WindowStyle.ToolWindow : WindowStyle.None,
WindowState = ShowMinimized ? WindowState.Minimized : WindowState.Normal,
Title = "NLog Messages"
};
TargetForm.Show();
TargetRichTextBox = new RichTextBox { Name = ControlName };
var style = new Style(typeof(Paragraph));
TargetRichTextBox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
style.Setters.Add(new Setter(Block.MarginProperty, new Thickness(0, 0, 0, 0)));
TargetRichTextBox.Resources.Add(typeof(Paragraph), style);
TargetForm.Content = TargetRichTextBox;
CreatedForm = true;
} }
var targetWindow = Application.Current.Windows.OfType<Window>().FirstOrDefault(w => w.Name == WindowName);
if (targetWindow == null)
{
InternalLogger.Info("{0}: WindowName '{1}' not found", this, WindowName);
return;
}
var targetControl = targetWindow.FindName(ControlName) as RichTextBox;
if (targetControl == null)
{
InternalLogger.Info("{0}: WIndowName '{1}' does not contain ControlName '{2}'", this, WindowName, ControlName);
return;
}
AttachToControl(targetWindow, targetControl);
}
private static void HandleError(string message, params object[] args)
{
if (LogManager.ThrowExceptions)
{
throw new NLogConfigurationException(string.Format(message, args));
}
InternalLogger.Error(message, args);
}
private void AttachToControl(Window window, RichTextBox textboxControl)
{
InternalLogger.Info("{0}: Attaching target to textbox {1}.{2}", this, window.Name, textboxControl.Name);
DetachFromControl();
TargetWindow = window;
TargetRichTextBox = textboxControl;
}
private void DetachFromControl()
{
TargetWindow = null;
TargetRichTextBox = null;
} }
protected override void CloseTarget() protected override void CloseTarget()
{ {
DetachFromControl(); if (CreatedForm)
{
try
{
TargetForm.Dispatcher.Invoke(() =>
{
TargetForm.Close();
TargetForm = null;
});
}
catch
{
}
}
} }
protected override void Write(LogEventInfo logEvent) protected override void Write(LogEventInfo logEvent)
{ {
RichTextBox textbox = TargetRichTextBox; RichTextBoxRowColoringRule matchingRule = RowColoringRules.FirstOrDefault(rr => rr.CheckCondition(logEvent));
if (textbox == null || textbox.Dispatcher.HasShutdownStarted || textbox.Dispatcher.HasShutdownFinished)
if (UseDefaultRowColoringRules && matchingRule == null)
{ {
//no last logged textbox foreach (var rr in DefaultRowColoringRules.Where(rr => rr.CheckCondition(logEvent)))
InternalLogger.Trace("{0}: Attached Textbox is {1}, skipping logging", this, textbox == null ? "null" : "disposed"); {
return; matchingRule = rr;
break;
}
} }
string logMessage = RenderLogEvent(Layout, logEvent); if (matchingRule == null)
RichTextBoxRowColoringRule matchingRule = FindMatchingRule(logEvent); {
_ = DoSendMessageToTextbox(logMessage, matchingRule, logEvent); matchingRule = RichTextBoxRowColoringRule.Default;
} }
var logMessage = Layout.Render(logEvent);
if (Application.Current == null) return;
private bool DoSendMessageToTextbox(string logMessage, RichTextBoxRowColoringRule rule, LogEventInfo logEvent)
{
RichTextBox textbox = TargetRichTextBox;
try try
{ {
if (textbox != null && !textbox.Dispatcher.HasShutdownStarted && !textbox.Dispatcher.HasShutdownFinished) if (Application.Current.Dispatcher.CheckAccess() == false)
{ {
if (!textbox.Dispatcher.CheckAccess()) Application.Current.Dispatcher.Invoke(() => SendTheMessageToRichTextBox(logMessage, matchingRule));
{ }
textbox.Dispatcher.BeginInvoke(() => SendTheMessageToRichTextBox(textbox, logMessage, rule, logEvent)); else
} {
else SendTheMessageToRichTextBox(logMessage, matchingRule);
{
SendTheMessageToRichTextBox(textbox, logMessage, rule, logEvent);
}
return true;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
InternalLogger.Warn(ex, "{0}: Failed to append RichTextBox", this); Debug.WriteLine(ex);
if (LogManager.ThrowExceptions)
{
throw;
}
} }
return false;
} }
private RichTextBoxRowColoringRule FindMatchingRule(LogEventInfo logEvent)
private static Color GetColorFromString(string color, Brush defaultColor)
{ {
//custom rules first
if (RowColoringRules.Count > 0) if (color == "Empty")
{ {
foreach (RichTextBoxRowColoringRule coloringRule in RowColoringRules) return defaultColor is SolidColorBrush solidBrush ? solidBrush.Color : Colors.White;
{
if (coloringRule.CheckCondition(logEvent))
{
return coloringRule;
}
}
} }
if (UseDefaultRowColoringRules && DefaultRowColoringRules != null) return (Color)colorConverter.ConvertFromString(color);
{
foreach (RichTextBoxRowColoringRule coloringRule in DefaultRowColoringRules)
{
if (coloringRule.CheckCondition(logEvent))
{
return coloringRule;
}
}
}
return RichTextBoxRowColoringRule.Default;
} }
private void SendTheMessageToRichTextBox(RichTextBox textBox, string logMessage, RichTextBoxRowColoringRule rule, LogEventInfo logEvent)
private void SendTheMessageToRichTextBox(string logMessage, RichTextBoxRowColoringRule rule)
{ {
if (textBox == null) return; RichTextBox rtbx = TargetRichTextBox;
var document = textBox.Document;
// 插入文本(带换行)
var tr = new TextRange(document.ContentEnd, document.ContentEnd)
{
Text = logMessage + Environment.NewLine
};
// 设置行级样式
var fgColor = rule.FontColor?.Render(logEvent);
var bgColor = rule.BackgroundColor?.Render(logEvent);
var tr = new TextRange(rtbx.Document.ContentEnd, rtbx.Document.ContentEnd);
tr.Text = logMessage + "\n";
tr.ApplyPropertyValue(TextElement.ForegroundProperty, tr.ApplyPropertyValue(TextElement.ForegroundProperty,
string.IsNullOrEmpty(fgColor) || fgColor == "Empty" new SolidColorBrush(GetColorFromString(rule.FontColor, (Brush)tr.GetPropertyValue(TextElement.ForegroundProperty)))
? textBox.Foreground );
: new SolidColorBrush((Color)ColorConverter.ConvertFromString(fgColor)));
tr.ApplyPropertyValue(TextElement.BackgroundProperty, tr.ApplyPropertyValue(TextElement.BackgroundProperty,
string.IsNullOrEmpty(bgColor) || bgColor == "Empty" new SolidColorBrush(GetColorFromString(rule.BackgroundColor, (Brush)tr.GetPropertyValue(TextElement.BackgroundProperty)))
? Brushes.Transparent );
: new SolidColorBrush((Color)ColorConverter.ConvertFromString(bgColor))); tr.ApplyPropertyValue(TextElement.FontStyleProperty, rule.Style);
tr.ApplyPropertyValue(TextElement.FontWeightProperty, rule.Weight);
tr.ApplyPropertyValue(TextElement.FontStyleProperty, rule.FontStyle);
tr.ApplyPropertyValue(TextElement.FontWeightProperty, rule.FontWeight);
// Word coloring在刚插入的范围内做匹配
if (WordColoringRules.Count > 0)
{
foreach (var wordRule in WordColoringRules)
{
var pattern = wordRule.Regex?.Render(logEvent) ?? string.Empty;
var text = wordRule.Text?.Render(logEvent) ?? string.Empty;
var wholeWords = wordRule.WholeWords.RenderValue(logEvent);
var ignoreCase = wordRule.IgnoreCase.RenderValue(logEvent);
var regex = wordRule.ResolveRegEx(pattern, text, wholeWords, ignoreCase);
var matches = regex.Matches(tr.Text);
foreach (Match match in matches)
{
// 匹配到的部分范围
var start = tr.Start.GetPositionAtOffset(match.Index, LogicalDirection.Forward);
var endPos = tr.Start.GetPositionAtOffset(match.Index + match.Length, LogicalDirection.Backward);
if (start == null || endPos == null) continue;
var wordRange = new TextRange(start, endPos);
var wordFg = wordRule.FontColor?.Render(logEvent);
var wordBg = wordRule.BackgroundColor?.Render(logEvent);
wordRange.ApplyPropertyValue(TextElement.ForegroundProperty,
string.IsNullOrEmpty(wordFg) || wordFg == "Empty"
? tr.GetPropertyValue(TextElement.ForegroundProperty)
: new SolidColorBrush((Color)ColorConverter.ConvertFromString(wordFg)));
wordRange.ApplyPropertyValue(TextElement.BackgroundProperty,
string.IsNullOrEmpty(wordBg) || wordBg == "Empty"
? tr.GetPropertyValue(TextElement.BackgroundProperty)
: new SolidColorBrush((Color)ColorConverter.ConvertFromString(wordBg)));
wordRange.ApplyPropertyValue(TextElement.FontStyleProperty, wordRule.FontStyle);
wordRange.ApplyPropertyValue(TextElement.FontWeightProperty, wordRule.FontWeight);
}
}
}
// 限制最大行数
if (MaxLines > 0) if (MaxLines > 0)
{ {
while (document.Blocks.Count > MaxLines) lineCount++;
if (lineCount > MaxLines)
{ {
document.Blocks.Remove(document.Blocks.FirstBlock); tr = new TextRange(rtbx.Document.ContentStart, rtbx.Document.ContentEnd);
tr.Text.Remove(0, tr.Text.IndexOf('\n'));
lineCount--;
} }
} }
// 自动滚动到最后
if (AutoScroll) if (AutoScroll)
{ {
textBox.ScrollToEnd(); rtbx.ScrollToEnd();
} }
} }
} }
} }

View File

@@ -1,59 +1,119 @@
using NLog.Config; //
using NLog.Layouts; // Copyright (c) 2004-2011 Jaroslaw Kowalski <jaak@jkowalski.net>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of Jaroslaw Kowalski nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//
using System.ComponentModel; using System.ComponentModel;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows; using System.Windows;
using NLog.Config;
namespace NLog.Windows.Wpf namespace NLog.Windows.Wpf
{ {
[NLogConfigurationItem] [NLogConfigurationItem]
public class RichTextBoxWordColoringRule public class RichTextBoxWordColoringRule
{ {
public Layout Regex { get; set; } private Regex compiledRegex;
public Layout Text { get; set; }
public Layout<bool> WholeWords { get; set; }
public Layout<bool> IgnoreCase { get; set; }
public Layout FontColor { get; set; } public RichTextBoxWordColoringRule()
public Layout BackgroundColor { get; set; }
public FontStyle FontStyle { get; set; }
public FontWeight FontWeight { get; set; }
internal Regex ResolveRegEx(string pattern, string text, bool wholeWords, bool ignoreCase)
{ {
if (string.IsNullOrEmpty(pattern) && text != null) FontColor = "Empty";
{ BackgroundColor = "Empty";
pattern = System.Text.RegularExpressions.Regex.Escape(text);
if (wholeWords)
pattern = "\b" + pattern + "\b";
}
RegexOptions options = RegexOptions.None;
if (ignoreCase)
options |= RegexOptions.IgnoreCase;
return new Regex(pattern, options); // RegEx-Cache
} }
public RichTextBoxWordColoringRule() : this(null, "Empty", "Empty", FontStyles.Normal, FontWeights.Normal) { }
public RichTextBoxWordColoringRule(string text, string fontColor, string backgroundColor) public RichTextBoxWordColoringRule(string text, string fontColor, string backgroundColor)
{ {
this.Text = text; Text = text;
this.FontColor = Layout.FromString(fontColor); FontColor = fontColor;
this.BackgroundColor = Layout.FromString(backgroundColor); BackgroundColor = backgroundColor;
this.FontStyle = FontStyles.Normal; Style = FontStyles.Normal;
this.FontWeight = FontWeights.Normal; Weight = FontWeights.Normal;
} }
public RichTextBoxWordColoringRule(string text, string textColor, string backgroundColor, FontStyle fontStyle, FontWeight fontWeight) public RichTextBoxWordColoringRule(string text, string textColor, string backgroundColor, FontStyle fontStyle, FontWeight fontWeight)
{ {
this.Text = text; Text = text;
this.FontColor = Layout.FromString(textColor); FontColor = textColor;
this.BackgroundColor = Layout.FromString(backgroundColor); BackgroundColor = backgroundColor;
this.FontStyle = fontStyle; Style = fontStyle;
this.FontWeight = fontWeight; Weight = fontWeight;
} }
public string Regex { get; set; }
public string Text { get; set; }
[DefaultValue(false)]
public bool WholeWords { get; set; }
[DefaultValue(false)]
public bool IgnoreCase { get; set; }
public FontStyle Style { get; set; }
public FontWeight Weight { get; set; }
public Regex CompiledRegex
{
get
{
if (compiledRegex == null)
{
string regexpression = Regex;
if (regexpression == null && Text != null)
{
regexpression = System.Text.RegularExpressions.Regex.Escape(Text);
if (WholeWords)
{
regexpression = "\b" + regexpression + "\b";
}
}
RegexOptions regexOptions = RegexOptions.Compiled;
if (IgnoreCase)
{
regexOptions |= RegexOptions.IgnoreCase;
}
compiledRegex = new Regex(regexpression, regexOptions);
}
return compiledRegex;
}
}
[DefaultValue("Empty")]
public string FontColor { get; set; }
[DefaultValue("Empty")]
public string BackgroundColor { get; set; }
} }
} }

View File

@@ -1,167 +1,136 @@
# [SpineViewer](https://github.com/ww-rm/SpineViewer) # [SpineViewer](https://github.com/ww-rm/SpineViewer)
[![Build and Release](https://github.com/ww-rm/SpineViewer/actions/workflows/dotnet-release.yml/badge.svg)](https://github.com/ww-rm/SpineViewer/actions/workflows/dotnet-release.yml) [![Build and Release](https://github.com/ww-rm/SpineViewer/actions/workflows/dotnet-desktop.yml/badge.svg)](https://github.com/ww-rm/SpineViewer/actions/workflows/dotnet-desktop.yml)
[![GitHub Release](https://img.shields.io/github/v/release/ww-rm/SpineViewer?logo=github\&logoColor=959da5\&label=Release\&labelColor=3f4850)](https://github.com/ww-rm/SpineViewer/releases) [![GitHub Release](https://img.shields.io/github/v/release/ww-rm/SpineViewer?logo=github\&logoColor=959da5\&label=Release\&labelColor=3f4850)](https://github.com/ww-rm/SpineViewer/releases)
[![Downloads](https://img.shields.io/github/downloads/ww-rm/SpineViewer/total?logo=github\&logoColor=959da5\&label=Downloads\&labelColor=3f4850)](https://github.com/ww-rm/SpineViewer/releases) [![Downloads](https://img.shields.io/github/downloads/ww-rm/SpineViewer/total?logo=github\&logoColor=959da5\&label=Downloads\&labelColor=3f4850)](https://github.com/ww-rm/SpineViewer/releases)
![Languages](https://img.shields.io/badge/Languages-中文%20%7C%20English%20%7C%20日本語-blue)
[中文](README.md) | [English](README.en.md) [中文](README.md) | [English](README.en.md)
Spine file viewer & exporter, also a dynamic wallpaper program supporting Spine animations. A simple and user-friendly Spine file viewer and exporter with multi-language support (Chinese/English/Japanese).
![previewer](https://github.com/user-attachments/assets/697ae86f-ddf0-445d-951c-cf04f5206e40) ![previewer](img/preview.webp)
[https://github.com/user-attachments/assets/37b6b730-088a-4352-827a-c338127a16f0](https://github.com/user-attachments/assets/37b6b730-088a-4352-827a-c338127a16f0)
---
## Features ## Features
- Supports multiple Spine file versions (`2.1.x; 3.4.x - 4.2.-`) * Supports multiple versions of Spine files.
- List-based multi-skeleton view with rendering order management * Batch open files via drag-and-drop or copy-paste.
- Supports multi-track animations * Batch preview functionality.
- Supports skin/slot/attachment settings * List-based multi-skeleton viewing and render order management.
- Debug rendering support * Batch adjustment of skeleton parameters using multi-selection.
- Frame rate / model / track time scale adjustment * Multi-track animation settings.
- Track alpha blending control * Skin and custom slot attachment settings.
- Export single frame / GIF / video * Custom slot visibility settings.
- Custom export via FFmpeg * Debug rendering support.
- Supports non-PNG texture formats * Fullscreen preview mode.
- Desktop dynamic wallpaper with auto-start support * Export to single frame/image sequence/animated GIF/video formats.
- ...... * Automatic resolution batch export.
* FFmpeg custom export support.
* Program parameter saving.
* ...
--- ### Supported Spine Versions
| Version | View & Export |
| :-----: | :------------------: |
| `2.1.x` | :white\_check\_mark: |
| `3.4.x` | :white\_check\_mark: |
| `3.5.x` | :white\_check\_mark: |
| `3.6.x` | :white\_check\_mark: |
| `3.7.x` | :white\_check\_mark: |
| `3.8.x` | :white\_check\_mark: |
| `4.0.x` | :white\_check\_mark: |
| `4.1.x` | :white\_check\_mark: |
| `4.2.x` | :white\_check\_mark: |
| `4.3.x` | |
More versions under development \:rocket: \:rocket: \:rocket:
### Supported Export Formats
| Format | Use Case |
| -------------- | ----------------------------------------------------------------------------- |
| Single Frame | Generate high-resolution images of models; manually adjust the desired frame. |
| Frame Sequence | Supports PNG format with transparency and lossless compression. |
| GIF/Video | Export preview animations or common video formats. |
| Custom Export | Supports arbitrary FFmpeg parameters for custom, complex export needs. |
## Installation ## Installation
Download the compressed package from the [Releases](https://github.com/ww-rm/SpineViewer/releases) page. Download the compressed package from the [Release](https://github.com/ww-rm/SpineViewer/releases) page.
The program requires the [.NET Desktop Runtime 8.0.x](https://dotnet.microsoft.com/download/dotnet/8.0) to be installed. The software requires the [.NET Desktop Runtime 8.0.x](https://dotnet.microsoft.com/download/dotnet/8.0) to run.
You can also download packages with the `SelfContained` suffix, which can run independently without additional installations. Alternatively, download the package with the `SelfContained` suffix for standalone execution.
Exporting GIF/MP4 or other animated/video formats requires **ffmpeg** installed locally and added to the system PATH. Download [FFmpeg for Windows](https://ffmpeg.org/download.html#build-windows) or the latest full build [ffmpeg-release-full.7z](https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z). For exporting GIF/MP4 and other animation/video formats, FFmpeg must be installed and added to the system environment variables. Visit the [FFmpeg Windows download page](https://ffmpeg.org/download.html#build-windows) or download the latest version directly: [ffmpeg-release-full.7z](https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z).
---
## Changing Display Language
Currently, the program supports the following interface languages:
- `ZH` (Chinese)
- `EN` (English)
- `JA` (Japanese)
Change the language via the menu: **File → Preferences… → Language**, then confirm.
---
## Usage ## Usage
### Overview ### How to Change the Display Language
The program uses a left-right layout: the left panel contains controls, the right panel displays the preview. In the menu, go to "File" -> "Preferences..." -> "Language," select your desired language, and confirm the change.
The left panel contains three sub-panels: ### Basic Overview
- **Models**: Lists imported and rendered models. Set model parameters, rendering order, and other model-related functions here. The program is organized into a left-right layout:
- **Browser**: Preview files in a folder without actually importing them. Generate WebP previews or import selected models.
- **Canvas**: Set parameters for the right-side preview display.
Most buttons, labels, or input fields show help text on hover. * **Left Panel:** Functionality panel.
* **Right Panel:** Preview display.
--- The left panel includes three sub-panels:
### Importing Skeletons * **Browse:** Preview the content of a specified folder without importing files into the program. This panel allows generating `.webp` previews for models or importing selected models.
* **Model:** Lists imported models for rendering. Parameters and rendering order can be adjusted here, along with other model-related functionalities.
* **Display:** Adjust parameters for the right-side preview display.
Drag-and-drop or paste skeleton files/folders directly into the **Models** panel. Hover your mouse over buttons, labels, or input fields to see help text for most UI elements.
Alternatively, use the right-click menu in the **Browser** panel to import selected items. ### Skeleton Import
--- Drag-and-drop or paste skeleton files/directories into the Model panel.
### Adjusting Content Alternatively, use the right-click menu in the Browse panel to import selected items.
The **Models** panel supports right-click menus, some hotkeys, and batch editing via multi-selection. ### Content Adjustment
Mouse interactions in the preview panel: The Model panel supports right-click menus, some shortcuts, and batch adjustments of model parameters through multi-selection.
- **Left click**: select and drag models. Hold `Ctrl` for multi-selection (synchronized with the model list). For preview display adjustments:
- **Right click**: drag the entire canvas.
- **Mouse wheel**: zoom in/out. Hold `Ctrl` to scale selected models together, use `Shift` to switch zoom factor.
- **Render selected only**: preview only the selected models, selection can only be changed via the left panel.
Playback controls below the preview allow time adjustment, acting as a simple player. * **Left-click:** Select and drag models. Hold `Ctrl` for multi-selection, synchronized with the left-side list.
* **Right-click:** Drag the entire display.
* **Scroll wheel:** Zoom in/out. Hold `Ctrl` to scale selected models.
* **Render selected-only mode:** In this mode, the preview only shows selected models, and selection status can only be changed via the left-side list.
--- The buttons below the preview display allow time adjustments, serving as a simple playback control.
### Exporting Content ### Content Export
Right-click on models in the list to access export options. Export follows the **WYSIWYG (What You See Is What You Get)** principle, meaning the preview display reflects the exported output.
Key export parameters: Use the right-click menu in the Model panel to export selected items.
- **Output folder**: Optional. If not provided, outputs go to each models folder. Otherwise, all outputs go to the specified folder. Key export parameters include:
- **Single export**: Default exports each model separately. If enabled, all selected models are rendered together in one output.
- **Auto resolution**: Ignores preview canvas resolution; exported resolution matches the actual size of content. For animations or videos, ensures full display of the animation.
--- * **Output folder:** Optional. When not specified, output is saved to the respective model folder; otherwise, all output is saved to the provided folder.
* **Export single:** By default, each model is exported independently. Selecting "Export single" renders all selected models in a single frame, producing a unified output.
* **Auto resolution:** Ignores the preview resolution and viewport parameters, exporting output at the actual size of the content. For animations/videos, the output matches the size required for full visibility.
### Dynamic Wallpaper ### More Information
The dynamic wallpaper projects the current preview content to the desktop in real time. For detailed usage and documentation, see the [Wiki](https://github.com/ww-rm/SpineViewer/wiki). For usage questions or bug reports, submit an [Issue](https://github.com/ww-rm/SpineViewer/issues).
Enable or disable via program preferences or the tray icon menu. Save workspace files to preserve model and canvas settings.
Auto-start with Windows can also be enabled, along with loading a specific workspace on startup.
---
### Command-line Tool
The project includes a CLI tool `SpineViewerCLI` for simple operations on a single model (querying parameters, exporting, etc.). Windows and Linux binaries are provided in Releases.
```bash
$ SpineViewerCLI -h
Description:
Root Command
Usage:
SpineViewerCLI [command] [options]
Options:
-q, --quiet Suppress console logging (quiet mode).
-?, -h, --help Show help and usage information
--version Show version information
Commands:
query <skel> Query information of single model
preview <skel> Preview a model
export <skel> Export single model
```
---
### More
Detailed instructions and usage guides can be found in the [Wiki](https://github.com/ww-rm/SpineViewer/wiki).
Report issues or bugs via [GitHub Issues](https://github.com/ww-rm/SpineViewer/issues).
---
## Acknowledgements ## Acknowledgements
- [spine-runtimes](https://github.com/EsotericSoftware/spine-runtimes) * [spine-runtimes](https://github.com/EsotericSoftware/spine-runtimes)
- [SFML.Net](https://github.com/SFML/SFML.Net) * [SFML.Net](https://github.com/SFML/SFML.Net)
- [FFMpegCore](https://github.com/rosenbjerg/FFMpegCore) * [FFMpegCore](https://github.com/rosenbjerg/FFMpegCore)
- [HandyControl](https://github.com/HandyOrg/HandyControl) * [HandyControl](https://github.com/HandyOrg/HandyControl)
- [NLog](https://github.com/NLog/NLog) * [NLog](https://github.com/NLog/NLog)
- [SkiaSharp](https://github.com/mono/SkiaSharp) * [SkiaSharp](https://github.com/mono/SkiaSharp)
- [Spectre.Console](https://github.com/spectreconsole/spectre.console)
--- ---
*If you like this project, please give it a :star: and share it with others! :\)* *If you find this project helpful, please give it a \:star: and share it with others! :)*
[![Stargazers over time](https://starchart.cc/ww-rm/SpineViewer.svg?variant=adaptive)](https://starchart.cc/ww-rm/SpineViewer) [![Stargazers over time](https://starchart.cc/ww-rm/SpineViewer.svg?variant=adaptive)](https://starchart.cc/ww-rm/SpineViewer)

109
README.md
View File

@@ -1,34 +1,59 @@
# [SpineViewer](https://github.com/ww-rm/SpineViewer) # [SpineViewer](https://github.com/ww-rm/SpineViewer)
[![Build and Release](https://github.com/ww-rm/SpineViewer/actions/workflows/dotnet-release.yml/badge.svg)](https://github.com/ww-rm/SpineViewer/actions/workflows/dotnet-release.yml) [![Build and Release](https://github.com/ww-rm/SpineViewer/actions/workflows/dotnet-desktop.yml/badge.svg)](https://github.com/ww-rm/SpineViewer/actions/workflows/dotnet-desktop.yml)
[![GitHub Release](https://img.shields.io/github/v/release/ww-rm/SpineViewer?logo=github&logoColor=959da5&label=Release&labelColor=3f4850)](https://github.com/ww-rm/SpineViewer/releases) [![GitHub Release](https://img.shields.io/github/v/release/ww-rm/SpineViewer?logo=github&logoColor=959da5&label=Release&labelColor=3f4850)](https://github.com/ww-rm/SpineViewer/releases)
[![Downloads](https://img.shields.io/github/downloads/ww-rm/SpineViewer/total?logo=github&logoColor=959da5&label=Downloads&labelColor=3f4850)](https://github.com/ww-rm/SpineViewer/releases) [![Downloads](https://img.shields.io/github/downloads/ww-rm/SpineViewer/total?logo=github&logoColor=959da5&label=Downloads&labelColor=3f4850)](https://github.com/ww-rm/SpineViewer/releases)
![Languages](https://img.shields.io/badge/Languages-中文%20%7C%20English%20%7C%20日本語-blue)
[中文](README.md) | [English](README.en.md) [中文](README.md) | [English](README.en.md)
Spine 文件查看&导出程序, 同时也是支持 Spine 的动态壁纸程序. 一个简单好用的 Spine 文件查看&导出程序, 支持中/英/日多语言界面.
![previewer](https://github.com/user-attachments/assets/697ae86f-ddf0-445d-951c-cf04f5206e40) ![previewer](img/preview.webp)
https://github.com/user-attachments/assets/37b6b730-088a-4352-827a-c338127a16f0
## 功能 ## 功能
- 支持多版本 spine 文件 (`2.1.x; 3.4.x - 4.2.x`) - 支持多版本 spine 文件
- 支持拖拽/复制粘贴批量打开文件
- 支持批量预览
- 支持列表式多骨骼查看和渲染层级管理 - 支持列表式多骨骼查看和渲染层级管理
- 支持多轨道动画 - 支持列表多选批量设置骨骼参数
- 支持皮肤/插槽/附件设置 - 支持多轨道动画设置
- 支持皮肤/自定义插槽附件设置
- 支持自定义插槽可见性
- 支持调试渲染 - 支持调试渲染
- 支持画面/模型/轨道时间倍速设置 - 支持全屏预览
- 支持设置轨道 Alpha 混合参数
- 支持单帧/动图/视频文件导出 - 支持单帧/动图/视频文件导出
- 支持自动分辨率批量导出
- 支持 FFmpeg 自定义导出 - 支持 FFmpeg 自定义导出
- 支持非 PNG 格式的纹理图片格式 - 支持程序参数保存
- 支持开机自启常驻动态壁纸
- ...... - ......
### Spine 版本支持
| 版本 | 查看&导出 |
| :---: | :---: |
| `2.1.x` | :white_check_mark: |
| `3.4.x` | :white_check_mark: |
| `3.5.x` | :white_check_mark: |
| `3.6.x` | :white_check_mark: |
| `3.7.x` | :white_check_mark: |
| `3.8.x` | :white_check_mark: |
| `4.0.x` | :white_check_mark: |
| `4.1.x` | :white_check_mark: |
| `4.2.x` | :white_check_mark: |
| `4.3.x` | |
更多版本正在施工 :rocket: :rocket: :rocket:
### 导出格式支持
| 导出格式 | 适用场景 |
| --- | --- |
| 单帧画面 | 支持生成高清模型画面图像, 可手动调节需要的一帧. |
| 帧序列 | 支持 PNG 格式帧序列, 可保留透明通道且无损压缩. |
| 动图/视频 | 可以生成预览动图或者常见格式视频. |
| 自定义导出 | 除上述预设方案, 支持提供任意 FFmpeg 参数进行导出, 满足自定义复杂需求. |
## 安装 ## 安装
前往 [Release](https://github.com/ww-rm/SpineViewer/releases) 界面下载压缩包. 前往 [Release](https://github.com/ww-rm/SpineViewer/releases) 界面下载压缩包.
@@ -39,26 +64,20 @@ https://github.com/user-attachments/assets/37b6b730-088a-4352-827a-c338127a16f0
导出 GIF/MP4 等动图/视频格式需要在本地安装 ffmpeg 命令行, 并且添加至环境变量, [点击前往 FFmpeg-Windows 下载页面](https://ffmpeg.org/download.html#build-windows), 也可以点这个下载最新版本 [ffmpeg-release-full.7z](https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z). 导出 GIF/MP4 等动图/视频格式需要在本地安装 ffmpeg 命令行, 并且添加至环境变量, [点击前往 FFmpeg-Windows 下载页面](https://ffmpeg.org/download.html#build-windows), 也可以点这个下载最新版本 [ffmpeg-release-full.7z](https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z).
## 修改显示语言
本项目目前支持以下界面显示语言:
- `ZH` (中文)
- `EN` (English)
- `JA` (日本語)
可以通过窗口菜单的 "文件" -> "首选项..." -> "语言", 选择你需要的语言并确认修改.
## 使用方法 ## 使用方法
### 如何修改显示语言
窗口菜单的 "文件" -> "首选项..." -> "语言", 选择你需要的语言并确认修改.
### 基本介绍 ### 基本介绍
程序大致是左右布局, 左侧是功能面板, 右侧是画面. 程序大致是左右布局, 左侧是功能面板, 右侧是画面.
左侧有三个子面板, 分别是: 左侧有三个子面板, 分别是:
- **模型**. 该面板记录导入并进行渲染的模型列表, 可以在这个面板设置与模型渲染相关的参数和渲染顺序, 以及一些与模型有关的功能.
- **浏览**. 该面板用于预览指定文件夹的内容, 并没有真正导入文件到程序. 在该面板可以为模型生成 webp 格式的预览图, 或者导入选中的模型. - **浏览**. 该面板用于预览指定文件夹的内容, 并没有真正导入文件到程序. 在该面板可以为模型生成 webp 格式的预览图, 或者导入选中的模型.
- **模型**. 该面板记录导入并进行渲染的模型列表, 可以在这个面板设置与模型渲染相关的参数和渲染顺序, 以及一些与模型有关的功能.
- **画面**. 该面板用于设置右侧预览画面的参数. - **画面**. 该面板用于设置右侧预览画面的参数.
绝大部分按钮或者标签或者输入框都可以通过鼠标指针悬停来获取帮助文本. 绝大部分按钮或者标签或者输入框都可以通过鼠标指针悬停来获取帮助文本.
@@ -77,14 +96,16 @@ https://github.com/user-attachments/assets/37b6b730-088a-4352-827a-c338127a16f0
- 左键可以选择和拖拽模型, 按下 `Ctrl` 键可以实现多选, 与左侧列表选择是联动的. - 左键可以选择和拖拽模型, 按下 `Ctrl` 键可以实现多选, 与左侧列表选择是联动的.
- 右键对整体画面进行拖动. - 右键对整体画面进行拖动.
- 滚轮进行画面缩放, 按住 `Ctrl` 可以对选中的模型进行批量缩放, `Shift` 可以切换缩放倍数. - 滚轮进行画面缩放, 按住 `Ctrl` 可以对选中的模型进行批量缩放.
- 仅渲染选中模式, 在该模式下, 预览画面仅包含被选中的模型, 并且只能通过左侧列表改变选中状态. - 仅渲染选中模式, 在该模式下, 预览画面仅包含被选中的模型, 并且只能通过左侧列表改变选中状态.
预览画面下方按钮支持对画面时间进行调整, 可以当作一个简易的播放器. 预览画面下方按钮支持对画面时间进行调整, 可以当作一个简易的播放器.
### 内容导出 ### 内容导出
在模型列表里, 右键单击选中的模型, 弹出菜单里可以对选中项执行导出操作. 导出遵循 "所见即所得" 原则, 即实时预览的画面就是你导出的画面.
在模型面板里, 右键菜单可以对选中项进行导出操作.
导出有以下几个关键参数: 导出有以下几个关键参数:
@@ -92,37 +113,6 @@ https://github.com/user-attachments/assets/37b6b730-088a-4352-827a-c338127a16f0
- 导出单个. 默认是每个模型独立导出, 即对模型列表进行批量操作, 如果选择仅导出单个, 那么被导出的所有模型将在同一个画面上被渲染, 输出产物只有一份. - 导出单个. 默认是每个模型独立导出, 即对模型列表进行批量操作, 如果选择仅导出单个, 那么被导出的所有模型将在同一个画面上被渲染, 输出产物只有一份.
- 自动分辨率. 该模式会忽略预览画面的分辨率和视区参数, 导出产物的分辨率与被导出内容的实际大小一致, 如果是动图或者视频则会与完整显示动画的必需大小一致. - 自动分辨率. 该模式会忽略预览画面的分辨率和视区参数, 导出产物的分辨率与被导出内容的实际大小一致, 如果是动图或者视频则会与完整显示动画的必需大小一致.
### 动态壁纸
动态壁纸通过桌面投影实现, 可以将当前预览画面上的内容实时投影至桌面.
在程序首选项或者托盘图标右键菜单中可以进行桌面投影的启用与否, 模型和画面参数调整完成后, 可以将当前参数保存为工作区文件, 方便之后恢复该配置.
如果希望开机自启常驻壁纸, 也可以在首选项中启用开机自启, 并且设置启动后需要加载的工作区文件.
### 命令行工具
项目附带一个纯命令行工具 `SpineViewerCLI`, 目前支持对单个模型执行一些简单操作, 例如参数值查询以及导出等, 并且 Release 界面提供 Windows 和 Linux 多平台二进制文件.
```bash
$ SpineViewerCLI -h
Description:
Root Command
Usage:
SpineViewerCLI [command] [options]
Options:
-q, --quiet Suppress console logging (quiet mode).
-?, -h, --help Show help and usage information
--version Show version information
Commands:
query <skel> Query information of single model
preview <skel> Preview a model
export <skel> Export single model
```
### 更多 ### 更多
更为详细的使用方法和说明见 [Wiki](https://github.com/ww-rm/SpineViewer/wiki), 有使用上的问题或者 BUG 可以提个 [Issue](https://github.com/ww-rm/SpineViewer/issues). 更为详细的使用方法和说明见 [Wiki](https://github.com/ww-rm/SpineViewer/wiki), 有使用上的问题或者 BUG 可以提个 [Issue](https://github.com/ww-rm/SpineViewer/issues).
@@ -135,10 +125,9 @@ Commands:
- [HandyControl](https://github.com/HandyOrg/HandyControl) - [HandyControl](https://github.com/HandyOrg/HandyControl)
- [NLog](https://github.com/NLog/NLog) - [NLog](https://github.com/NLog/NLog)
- [SkiaSharp](https://github.com/mono/SkiaSharp) - [SkiaSharp](https://github.com/mono/SkiaSharp)
- [Spectre.Console](https://github.com/spectreconsole/spectre.console)
--- ---
*如果你觉得这个项目不错请给个 :star:, 并分享给更多人知道! :\)* *如果你觉得这个项目不错请给个 :star:, 并分享给更多人知道! :)*
[![Stargazers over time](https://starchart.cc/ww-rm/SpineViewer.svg?variant=adaptive)](https://starchart.cc/ww-rm/SpineViewer) [![Stargazers over time](https://starchart.cc/ww-rm/SpineViewer.svg?variant=adaptive)](https://starchart.cc/ww-rm/SpineViewer)

View File

@@ -64,10 +64,10 @@ namespace SFMLRenderer
hs?.Dispose(); hs?.Dispose();
} }
private IntPtr HwndMessageHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) private nint HwndMessageHook(nint hwnd, int msg, nint wParam, nint lParam, ref bool handled)
{ {
_renderWindow?.DispatchEvents(); _renderWindow?.DispatchEvents();
return IntPtr.Zero; return nint.Zero;
} }
} }
} }

View File

@@ -240,8 +240,8 @@ namespace SFMLRenderer
if (RenderWindow is null) return; if (RenderWindow is null) return;
float parentW = (float)sizeInfo.NewSize.Width; float parentW = (float)sizeInfo.NewSize.Width;
float parentH = (float)sizeInfo.NewSize.Height; float parentH = (float)sizeInfo.NewSize.Height;
float renderW = _resolution.X; float renderW = (float)_hwndHost.ActualWidth;
float renderH = _resolution.Y; float renderH = (float)_hwndHost.ActualHeight;
float scale = Math.Min(parentW / renderW, parentH / renderH); // 两方向取较小值, 保证 parent 覆盖 render float scale = Math.Min(parentW / renderW, parentH / renderH); // 两方向取较小值, 保证 parent 覆盖 render
renderW *= scale; renderW *= scale;
renderH *= scale; renderH *= scale;

View File

@@ -1,180 +0,0 @@
using SFML.Graphics;
using SFML.System;
using SFML.Window;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;
using Win32Natives;
namespace SFMLRenderer
{
public class SFMLRenderWindow : RenderWindow, ISFMLRenderer
{
private readonly DispatcherTimer _timer = new() { Interval = TimeSpan.FromMilliseconds(10) };
public SFMLRenderWindow(VideoMode mode, string title, Styles style) : base(mode, title, style)
{
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);
}
public event EventHandler? RendererCreated;
public event EventHandler? RendererDisposing
{
add => throw new NotImplementedException();
remove => throw new NotImplementedException();
}
public event EventHandler<MouseMoveEventArgs>? CanvasMouseMove
{
add { MouseMoved += value; }
remove { MouseMoved -= value; }
}
public event EventHandler<MouseButtonEventArgs>? CanvasMouseButtonPressed
{
add { MouseButtonPressed += value; }
remove { MouseButtonPressed -= value; }
}
public event EventHandler<MouseButtonEventArgs>? CanvasMouseButtonReleased
{
add { MouseButtonReleased += value; }
remove { MouseButtonReleased -= value; }
}
public event EventHandler<MouseWheelScrollEventArgs>? CanvasMouseWheelScrolled
{
add { MouseWheelScrolled += value; }
remove { MouseWheelScrolled -= value; }
}
public Vector2u Resolution
{
get => Size;
set => Size = value;
}
public Vector2f Center
{
get
{
using var view = GetView();
return view.Center;
}
set
{
using var view = GetView();
view.Center = value;
SetView(view);
}
}
public float Zoom
{
get
{
using var view = GetView();
return Math.Abs(Size.X / view.Size.X); // XXX: 仅使用宽度进行缩放计算
}
set
{
value = Math.Abs(value);
if (value <= 0) return;
using var view = GetView();
var signX = Math.Sign(view.Size.X);
var signY = Math.Sign(view.Size.Y);
var resolution = Size;
view.Size = new(resolution.X / value * signX, resolution.Y / value * signY);
SetView(view);
}
}
public float Rotation
{
get
{
using var view = GetView();
return view.Rotation;
}
set
{
using var view = GetView();
view.Rotation = value;
SetView(view);
}
}
public bool FlipX
{
get
{
using var view = GetView();
return view.Size.X < 0;
}
set
{
using var view = GetView();
var size = view.Size;
if (size.X > 0 && value || size.X < 0 && !value)
size.X *= -1;
view.Size = size;
SetView(view);
}
}
public bool FlipY
{
get
{
using var view = GetView();
return view.Size.Y < 0;
}
set
{
using var view = GetView();
var size = view.Size;
if (size.Y > 0 && value || size.Y < 0 && !value)
size.Y *= -1;
view.Size = size;
SetView(view);
}
}
public uint MaxFps
{
get => _maxFps;
set
{
SetFramerateLimit(value);
_maxFps = value;
}
}
private uint _maxFps = 0;
public bool VerticalSync
{
get => _verticalSync;
set
{
SetVerticalSyncEnabled(value);
_verticalSync = value;
}
}
private bool _verticalSync = false;
}
}

View File

@@ -4,14 +4,10 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
<PlatformTarget>x64</PlatformTarget>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net8.0-windows</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath> <BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
<OutputPath>$(BaseOutputPath)\$(Configuration)\$(PlatformTarget)</OutputPath>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion> <IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<Version>0.16.6</Version> <Version>0.15.4</Version>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
</PropertyGroup> </PropertyGroup>
@@ -23,8 +19,4 @@
<PackageReference Include="SFML.Net" Version="2.6.1" /> <PackageReference Include="SFML.Net" Version="2.6.1" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Win32Natives\Win32Natives.csproj" />
</ItemGroup>
</Project> </Project>

View File

@@ -14,14 +14,6 @@ namespace Spine.Exporters
/// </summary> /// </summary>
public abstract class BaseExporter : IDisposable public abstract class BaseExporter : IDisposable
{ {
/// <summary>
/// 进度回调函数
/// </summary>
/// <param name="total">任务总量</param>
/// <param name="done">已完成量</param>
/// <param name="promptText">需要设置的进度提示文本</param>
public delegate void ProgressReporterHandler(float total, float done, string promptText);
/// <summary> /// <summary>
/// 日志器 /// 日志器
/// </summary> /// </summary>
@@ -64,9 +56,14 @@ namespace Spine.Exporters
/// <summary> /// <summary>
/// 可选的进度回调函数 /// 可选的进度回调函数
/// <list type="number">
/// <item><c>total</c>: 任务总量</item>
/// <item><c>done</c>: 已完成量</item>
/// <item><c>progressText</c>: 需要设置的进度提示文本</item>
/// </list>
/// </summary> /// </summary>
public ProgressReporterHandler? ProgressReporter { get => _progressReporter; set => _progressReporter = value; } public Action<float, float, string>? ProgressReporter { get => _progressReporter; set => _progressReporter = value; }
protected ProgressReporterHandler? _progressReporter; protected Action<float, float, string>? _progressReporter;
/// <summary> /// <summary>
/// 背景颜色 /// 背景颜色

View File

@@ -92,7 +92,7 @@ namespace Spine.Exporters
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Debug(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to export {0} {1}, {2}", _format, output, ex.Message); _logger.Error("Failed to export {0} {1}, {2}", _format, output, ex.Message);
} }
} }

View File

@@ -28,40 +28,12 @@ namespace Spine.Exporters
{ {
Gif, Gif,
Webp, Webp,
Apng,
Mp4, Mp4,
Webm, Webm,
Mkv, Mkv,
Mov, Mov,
} }
/// <summary>
/// Apng 格式预测器算法
/// </summary>
public enum ApngPredMethod
{
None = 0,
Sub = 1,
Up = 2,
Avg = 3,
Paeth = 4,
Mixed = 5,
}
/// <summary>
/// Mov prores_ks 编码器 profile 参数
/// </summary>
public enum MovProfile
{
Auto = -1,
Proxy = 0,
Light = 1,
Standard = 2,
High = 3,
Yuv4444 = 4,
Yuv4444Extreme = 5,
}
/// <summary> /// <summary>
/// 视频格式 /// 视频格式
/// </summary> /// </summary>
@@ -69,40 +41,34 @@ namespace Spine.Exporters
private VideoFormat _format = VideoFormat.Mp4; private VideoFormat _format = VideoFormat.Mp4;
/// <summary> /// <summary>
/// [Gif/Webp/Apng] 动图是否循环 /// 动图是否循环 [Gif/Webp]
/// </summary> /// </summary>
public bool Loop { get => _loop; set => _loop = value; } public bool Loop { get => _loop; set => _loop = value; }
private bool _loop = true; private bool _loop = true;
/// <summary> /// <summary>
/// [Webp] 质量 /// 质量 [Webp]
/// </summary> /// </summary>
public int Quality { get => _quality; set => _quality = Math.Clamp(value, 0, 100); } public int Quality { get => _quality; set => _quality = Math.Clamp(value, 0, 100); }
private int _quality = 75; private int _quality = 75;
/// <summary> /// <summary>
/// [Webp] 无损压缩 /// 无损压缩 [Webp]
/// </summary> /// </summary>
public bool Lossless { get => _lossless; set => _lossless = value; } public bool Lossless { get => _lossless; set => _lossless = value; }
private bool _lossless = false; private bool _lossless = false;
/// <summary> /// <summary>
/// [Apng] 预测器算法 /// CRF [Mp4/Webm/Mkv]
/// </summary>
public ApngPredMethod PredMethod { get => _predMethod; set => _predMethod = value; }
private ApngPredMethod _predMethod = ApngPredMethod.Mixed;
/// <summary>
/// [Mp4/Webm/Mkv] CRF
/// </summary> /// </summary>
public int Crf { get => _crf; set => _crf = Math.Clamp(value, 0, 63); } public int Crf { get => _crf; set => _crf = Math.Clamp(value, 0, 63); }
private int _crf = 23; private int _crf = 23;
/// <summary> /// <summary>
/// [Mov] prores_ks 编码器的配置等级, 越高质量越好, 只有 <see cref="MovProfile.Yuv4444"> 及以上才有透明通道 /// prores_ks 编码器的配置等级, -1 是自动, 越高质量越好, 只有 4 及以上才有透明通道 [Mov]
/// </summary> /// </summary>
public MovProfile Profile { get => _profile; set => _profile = value; } public int Profile { get => _profile; set => _profile = Math.Clamp(value, -1, 5); }
private MovProfile _profile = MovProfile.Yuv4444Extreme; private int _profile = 5;
/// <summary> /// <summary>
/// 获取的一帧, 结果是预乘的 /// 获取的一帧, 结果是预乘的
@@ -127,7 +93,6 @@ namespace Spine.Exporters
{ {
VideoFormat.Gif => SetGifOptions, VideoFormat.Gif => SetGifOptions,
VideoFormat.Webp => SetWebpOptions, VideoFormat.Webp => SetWebpOptions,
VideoFormat.Apng => SetApngOptions,
VideoFormat.Mp4 => SetMp4Options, VideoFormat.Mp4 => SetMp4Options,
VideoFormat.Webm => SetWebmOptions, VideoFormat.Webm => SetWebmOptions,
VideoFormat.Mkv => SetMkvOptions, VideoFormat.Mkv => SetMkvOptions,
@@ -144,7 +109,7 @@ namespace Spine.Exporters
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Debug(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to export {0} {1}, {2}", _format, output, ex.Message); _logger.Error("Failed to export {0} {1}, {2}", _format, output, ex.Message);
} }
} }
@@ -167,13 +132,6 @@ namespace Spine.Exporters
.WithCustomArgument(customArgs); .WithCustomArgument(customArgs);
} }
private void SetApngOptions(FFMpegArgumentOptions options)
{
var customArgs = $"-vf unpremultiply=inplace=1 -plays {(_loop ? 0 : 1)} -pred {(int)_predMethod}";
options.ForceFormat("apng").WithVideoCodec("apng").ForcePixelFormat("rgba")
.WithCustomArgument(customArgs);
}
private void SetMp4Options(FFMpegArgumentOptions options) private void SetMp4Options(FFMpegArgumentOptions options)
{ {
// XXX: windows 默认播放器在播放 MP4 格式时对于 libx264 编码器只支持 yuv420p 的像素格式 // XXX: windows 默认播放器在播放 MP4 格式时对于 libx264 编码器只支持 yuv420p 的像素格式
@@ -206,7 +164,7 @@ namespace Spine.Exporters
var customArgs = "-vf unpremultiply=inplace=1"; var customArgs = "-vf unpremultiply=inplace=1";
options.ForceFormat("mov").WithVideoCodec("prores_ks").ForcePixelFormat("yuva444p10le") options.ForceFormat("mov").WithVideoCodec("prores_ks").ForcePixelFormat("yuva444p10le")
.WithFastStart() .WithFastStart()
.WithCustomArgument($"-profile {(int)_profile}") .WithCustomArgument($"-profile {_profile}")
.WithCustomArgument(customArgs); .WithCustomArgument(customArgs);
} }
} }

View File

@@ -18,27 +18,11 @@ namespace Spine.Exporters
public FrameExporter(uint width = 100, uint height = 100) : base(width, height) { } public FrameExporter(uint width = 100, uint height = 100) : base(width, height) { }
public FrameExporter(Vector2u resolution) : base(resolution) { } public FrameExporter(Vector2u resolution) : base(resolution) { }
public SKEncodedImageFormat Format public SKEncodedImageFormat Format { get => _format; set => _format = value; }
{
get => _format;
set {
switch (value)
{
case SKEncodedImageFormat.Jpeg:
case SKEncodedImageFormat.Png:
case SKEncodedImageFormat.Webp:
_format = value;
break;
default:
_logger.Warn("Omit unsupported exporter format: {0}", value);
break;
}
}
}
protected SKEncodedImageFormat _format = SKEncodedImageFormat.Png; protected SKEncodedImageFormat _format = SKEncodedImageFormat.Png;
public int Quality { get => _quality; set => _quality = Math.Clamp(value, 0, 100); } public int Quality { get => _quality; set => _quality = Math.Clamp(value, 0, 100); }
protected int _quality = 100; protected int _quality = 80;
public override void Export(string output, params SpineObject[] spines) public override void Export(string output, params SpineObject[] spines)
{ {
@@ -49,15 +33,5 @@ namespace Spine.Exporters
using var stream = File.OpenWrite(output); using var stream = File.OpenWrite(output);
data.SaveTo(stream); data.SaveTo(stream);
} }
/// <summary>
/// 获取帧图像, 结果是预乘的
/// </summary>
public SKImage ExportMemoryImage(params SpineObject[] spines)
{
using var frame = GetFrame(spines);
var info = new SKImageInfo(frame.Width, frame.Height, SKColorType.Rgba8888, SKAlphaType.Premul);
return SKImage.FromPixelCopy(info, frame.Image.Pixels);
}
} }
} }

View File

@@ -24,7 +24,7 @@ namespace Spine.Exporters
int frameCount = GetFrameCount(); int frameCount = GetFrameCount();
int frameIdx = 0; int frameIdx = 0;
_progressReporter?.Invoke(frameCount, 0, $"[0/{frameCount}] {output}"); // 导出帧序列单独在此处调用进度报告 _progressReporter?.Invoke(frameCount, 0, $"[{frameIdx}/{frameCount}] {output}");
foreach (var frame in GetFrames(spines)) foreach (var frame in GetFrames(spines))
{ {
if (ct.IsCancellationRequested) if (ct.IsCancellationRequested)
@@ -37,7 +37,7 @@ namespace Spine.Exporters
var savePath = Path.Combine(output, $"frame_{_fps}_{frameIdx:d6}.png"); var savePath = Path.Combine(output, $"frame_{_fps}_{frameIdx:d6}.png");
var info = new SKImageInfo(frame.Width, frame.Height, SKColorType.Rgba8888, SKAlphaType.Premul); var info = new SKImageInfo(frame.Width, frame.Height, SKColorType.Rgba8888, SKAlphaType.Premul);
_progressReporter?.Invoke(frameCount, frameIdx + 1, $"[{frameIdx + 1}/{frameCount}] {savePath}"); _progressReporter?.Invoke(frameCount, frameIdx, $"[{frameIdx + 1}/{frameCount}] {savePath}");
try try
{ {
using var skImage = SKImage.FromPixelCopy(info, frame.Image.Pixels); using var skImage = SKImage.FromPixelCopy(info, frame.Image.Pixels);
@@ -47,7 +47,7 @@ namespace Spine.Exporters
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Debug(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to save frame {0}, {1}", savePath, ex.Message); _logger.Error("Failed to save frame {0}, {1}", savePath, ex.Message);
} }
finally finally

View File

@@ -92,7 +92,7 @@ namespace Spine.Exporters
} }
/// <summary> /// <summary>
/// 生成帧序列, 用于导出帧序列 /// 生成帧序列
/// </summary> /// </summary>
protected IEnumerable<SFMLImageVideoFrame> GetFrames(SpineObject[] spines) protected IEnumerable<SFMLImageVideoFrame> GetFrames(SpineObject[] spines)
{ {
@@ -121,14 +121,14 @@ namespace Spine.Exporters
} }
/// <summary> /// <summary>
/// 生成帧序列, 支持中途取消和进度输出, 用于动图视频等单个文件输出 /// 生成帧序列, 支持中途取消和进度输出
/// </summary> /// </summary>
protected IEnumerable<SFMLImageVideoFrame> GetFrames(SpineObject[] spines, string output, CancellationToken ct) protected IEnumerable<SFMLImageVideoFrame> GetFrames(SpineObject[] spines, string output, CancellationToken ct)
{ {
int frameCount = GetFrameCount(); int frameCount = GetFrameCount();
int frameIdx = 0; int frameIdx = 0;
_progressReporter?.Invoke(frameCount, 0, $"[0/{frameCount}] {output}"); _progressReporter?.Invoke(frameCount, 0, $"[{frameIdx}/{frameCount}] {output}");
foreach (var frame in GetFrames(spines)) foreach (var frame in GetFrames(spines))
{ {
if (ct.IsCancellationRequested) if (ct.IsCancellationRequested)
@@ -138,7 +138,7 @@ namespace Spine.Exporters
break; break;
} }
_progressReporter?.Invoke(frameCount, frameIdx + 1, $"[{frameIdx + 1}/{frameCount}] {output}"); _progressReporter?.Invoke(frameCount, frameIdx, $"[{frameIdx + 1}/{frameCount}] {output}");
yield return frame; yield return frame;
frameIdx++; frameIdx++;
} }

View File

@@ -1,4 +1,4 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime21; using SpineRuntime21;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,7 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V21 namespace Spine.Implementations.SpineWrappers.V21
{ {
internal sealed class Animation21(Animation innerObject) : IAnimation internal sealed class Animation21(Animation innerObject) : IAnimation
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime21; using SpineRuntime21;
namespace Spine.Implementations.V21 namespace Spine.Implementations.SpineWrappers.V21
{ {
internal sealed class AnimationState21(AnimationState innerObject, SpineObjectData21 data) : IAnimationState internal sealed class AnimationState21(AnimationState innerObject, SpineObjectData21 data) : IAnimationState
{ {
@@ -35,7 +35,7 @@ namespace Spine.Implementations.V21
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Start += f; _o.Start += f;
@@ -64,7 +64,7 @@ namespace Spine.Implementations.V21
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.End += f; _o.End += f;
@@ -93,7 +93,7 @@ namespace Spine.Implementations.V21
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Complete += f; _o.Complete += f;

View File

@@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using Spine.Interfaces.Attachments; using Spine.SpineWrappers.Attachments;
using SpineRuntime21; using SpineRuntime21;
namespace Spine.Implementations.V21.Attachments namespace Spine.Implementations.SpineWrappers.V21.Attachments
{ {
internal abstract class Attachment21(Attachment innerObject) : IAttachment internal abstract class Attachment21(Attachment innerObject) : IAttachment
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V21; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime21; using SpineRuntime21;
namespace Spine.Implementations.V21.Attachments namespace Spine.Implementations.SpineWrappers.V21.Attachments
{ {
internal sealed class BoundingBoxAttachment21(BoundingBoxAttachment innerObject) : internal sealed class BoundingBoxAttachment21(BoundingBoxAttachment innerObject) :
Attachment21(innerObject), Attachment21(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V21.Attachments
public override BoundingBoxAttachment InnerObject => _o; public override BoundingBoxAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot21 st) if (slot is Slot21 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V21; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime21; using SpineRuntime21;
namespace Spine.Implementations.V21.Attachments namespace Spine.Implementations.SpineWrappers.V21.Attachments
{ {
internal sealed class MeshAttachment21(MeshAttachment innerObject) : internal sealed class MeshAttachment21(MeshAttachment innerObject) :
Attachment21(innerObject), Attachment21(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V21.Attachments
public override MeshAttachment InnerObject => _o; public override MeshAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot21 st) if (slot is Slot21 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V21; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime21; using SpineRuntime21;
namespace Spine.Implementations.V21.Attachments namespace Spine.Implementations.SpineWrappers.V21.Attachments
{ {
internal sealed class RegionAttachment21(RegionAttachment innerObject) : internal sealed class RegionAttachment21(RegionAttachment innerObject) :
Attachment21(innerObject), Attachment21(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V21.Attachments
public override RegionAttachment InnerObject => _o; public override RegionAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot21 st) if (slot is Slot21 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V21; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime21; using SpineRuntime21;
namespace Spine.Implementations.V21.Attachments namespace Spine.Implementations.SpineWrappers.V21.Attachments
{ {
internal sealed class SkinnedMeshAttachment21(SkinnedMeshAttachment innerObject) : internal sealed class SkinnedMeshAttachment21(SkinnedMeshAttachment innerObject) :
Attachment21(innerObject), Attachment21(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V21.Attachments
public override SkinnedMeshAttachment InnerObject => _o; public override SkinnedMeshAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot21 st) if (slot is Slot21 st)
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime21; using SpineRuntime21;
namespace Spine.Implementations.V21 namespace Spine.Implementations.SpineWrappers.V21
{ {
internal sealed class Bone21(Bone innerObject, Bone21? parent = null) : IBone internal sealed class Bone21(Bone innerObject, Bone21? parent = null) : IBone
{ {

View File

@@ -5,10 +5,10 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Frozen; using System.Collections.Frozen;
using System.Collections.Immutable; using System.Collections.Immutable;
using Spine.SpineWrappers;
using SpineRuntime21; using SpineRuntime21;
using Spine.Interfaces;
namespace Spine.Implementations.V21 namespace Spine.Implementations.SpineWrappers.V21
{ {
internal sealed class Skeleton21 : ISkeleton internal sealed class Skeleton21 : ISkeleton
{ {
@@ -52,7 +52,6 @@ namespace Spine.Implementations.V21
public Skeleton InnerObject => _o; public Skeleton InnerObject => _o;
public string Name => _o.Data.Name;
public float R { get => _o.R; set => _o.R = value; } public float R { get => _o.R; set => _o.R = value; }
public float G { get => _o.G; set => _o.G = value; } public float G { get => _o.G; set => _o.G = value; }
public float B { get => _o.B; set => _o.B = value; } public float B { get => _o.B; set => _o.B = value; }
@@ -96,6 +95,11 @@ namespace Spine.Implementations.V21
public void SetSlotsToSetupPose() => _o.SetSlotsToSetupPose(); public void SetSlotsToSetupPose() => _o.SetSlotsToSetupPose();
public void Update(float delta) => _o.Update(delta); public void Update(float delta) => _o.Update(delta);
public void GetBounds(out float x, out float y, out float w, out float h)
{
_o.GetBounds(out x, out y, out w, out h);
}
public override string ToString() => _o.ToString(); public override string ToString() => _o.ToString();
} }
} }

View File

@@ -1,5 +1,5 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using Spine.Interfaces.Attachments; using Spine.SpineWrappers.Attachments;
using Spine.Utils; using Spine.Utils;
using SpineRuntime21; using SpineRuntime21;
using System; using System;
@@ -8,7 +8,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V21 namespace Spine.Implementations.SpineWrappers.V21
{ {
internal sealed class SkeletonClipping21 : ISkeletonClipping internal sealed class SkeletonClipping21 : ISkeletonClipping
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime21; using SpineRuntime21;
namespace Spine.Implementations.V21 namespace Spine.Implementations.SpineWrappers.V21
{ {
internal sealed class Skin21 : ISkin internal sealed class Skin21 : ISkin
{ {

View File

@@ -5,11 +5,10 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Utils; using Spine.Utils;
using Spine.SpineWrappers;
using SpineRuntime21; using SpineRuntime21;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
namespace Spine.Implementations.V21 namespace Spine.Implementations.SpineWrappers.V21
{ {
internal sealed class Slot21 : ISlot internal sealed class Slot21 : ISlot
{ {
@@ -40,7 +39,7 @@ namespace Spine.Implementations.V21
public float A { get => _o.A; set => _o.A = value; } public float A { get => _o.A; set => _o.A = value; }
public IBone Bone => _bone; public IBone Bone => _bone;
public IAttachment? Attachment public Spine.SpineWrappers.Attachments.IAttachment? Attachment
{ {
get get
{ {

View File

@@ -6,12 +6,12 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Utils; using Spine.Utils;
using Spine.SpineWrappers;
using Spine.SpineWrappers.Attachments;
using SpineRuntime21; using SpineRuntime21;
using Spine.Implementations.V21.Attachments; using Spine.Implementations.SpineWrappers.V21.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
namespace Spine.Implementations.V21 namespace Spine.Implementations.SpineWrappers.V21
{ {
[SpineImplementation(2, 1)] [SpineImplementation(2, 1)]
internal sealed class SpineObjectData21 : SpineObjectData internal sealed class SpineObjectData21 : SpineObjectData
@@ -26,19 +26,12 @@ namespace Spine.Implementations.V21
private readonly ImmutableArray<IAnimation> _animations; private readonly ImmutableArray<IAnimation> _animations;
private readonly FrozenDictionary<string, IAnimation> _animationsByName; private readonly FrozenDictionary<string, IAnimation> _animationsByName;
public SpineObjectData21(string skelPath, string atlasPath, TextureLoader textureLoader) public SpineObjectData21(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader)
: base(skelPath, atlasPath, textureLoader) : base(skelPath, atlasPath, textureLoader)
{ {
// 加载 atlas // 加载 atlas
try try { _atlas = new Atlas(atlasPath, textureLoader); }
{ catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Debug(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
try try
{ {
@@ -48,9 +41,8 @@ namespace Spine.Implementations.V21
{ {
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
} }
catch (Exception ex) catch
{ {
_logger.Debug(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
} }
} }
@@ -60,9 +52,8 @@ namespace Spine.Implementations.V21
{ {
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
} }
catch (Exception ex) catch
{ {
_logger.Debug(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
} }
} }
@@ -70,8 +61,7 @@ namespace Spine.Implementations.V21
catch (Exception ex) catch (Exception ex)
{ {
_atlas.Dispose(); _atlas.Dispose();
_logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
} }
// 加载动画数据 // 加载动画数据

View File

@@ -1,4 +1,4 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime21; using SpineRuntime21;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,7 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V21 namespace Spine.Implementations.SpineWrappers.V21
{ {
internal sealed class TrackEntry21(TrackEntry innerObject, AnimationState21 animationState, SpineObjectData21 data): ITrackEntry internal sealed class TrackEntry21(TrackEntry innerObject, AnimationState21 animationState, SpineObjectData21 data): ITrackEntry
{ {
@@ -34,7 +34,7 @@ namespace Spine.Implementations.V21
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Start += f; _o.Start += f;
@@ -63,7 +63,7 @@ namespace Spine.Implementations.V21
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.End += f; _o.End += f;
@@ -92,7 +92,7 @@ namespace Spine.Implementations.V21
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Complete += f; _o.Complete += f;

View File

@@ -1,4 +1,4 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime34; using SpineRuntime34;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,7 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V34 namespace Spine.Implementations.SpineWrappers.V34
{ {
internal sealed class Animation34(Animation innerObject) : IAnimation internal sealed class Animation34(Animation innerObject) : IAnimation
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime34; using SpineRuntime34;
namespace Spine.Implementations.V34 namespace Spine.Implementations.SpineWrappers.V34
{ {
internal sealed class AnimationState34(AnimationState innerObject, SpineObjectData34 data) : IAnimationState internal sealed class AnimationState34(AnimationState innerObject, SpineObjectData34 data) : IAnimationState
{ {
@@ -36,7 +36,7 @@ namespace Spine.Implementations.V34
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Start += f; _o.Start += f;
@@ -65,7 +65,7 @@ namespace Spine.Implementations.V34
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.End += f; _o.End += f;
@@ -94,7 +94,7 @@ namespace Spine.Implementations.V34
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Complete += f; _o.Complete += f;

View File

@@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using Spine.Interfaces.Attachments; using Spine.SpineWrappers.Attachments;
using SpineRuntime34; using SpineRuntime34;
namespace Spine.Implementations.V34.Attachments namespace Spine.Implementations.SpineWrappers.V34.Attachments
{ {
internal abstract class Attachment34(Attachment innerObject) : IAttachment internal abstract class Attachment34(Attachment innerObject) : IAttachment
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V34; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime34; using SpineRuntime34;
namespace Spine.Implementations.V34.Attachments namespace Spine.Implementations.SpineWrappers.V34.Attachments
{ {
internal sealed class BoundingBoxAttachment34(BoundingBoxAttachment innerObject) : internal sealed class BoundingBoxAttachment34(BoundingBoxAttachment innerObject) :
Attachment34(innerObject), Attachment34(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V34.Attachments
public override BoundingBoxAttachment InnerObject => _o; public override BoundingBoxAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot34 st) if (slot is Slot34 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V34; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime34; using SpineRuntime34;
namespace Spine.Implementations.V34.Attachments namespace Spine.Implementations.SpineWrappers.V34.Attachments
{ {
internal sealed class MeshAttachment34(MeshAttachment innerObject) : internal sealed class MeshAttachment34(MeshAttachment innerObject) :
Attachment34(innerObject), Attachment34(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V34.Attachments
public override MeshAttachment InnerObject => _o; public override MeshAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot34 st) if (slot is Slot34 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V34; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime34; using SpineRuntime34;
namespace Spine.Implementations.V34.Attachments namespace Spine.Implementations.SpineWrappers.V34.Attachments
{ {
internal sealed class PathAttachment34(PathAttachment innerObject) : internal sealed class PathAttachment34(PathAttachment innerObject) :
Attachment34(innerObject), Attachment34(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V34.Attachments
public override PathAttachment InnerObject => _o; public override PathAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot34 st) if (slot is Slot34 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V34; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime34; using SpineRuntime34;
namespace Spine.Implementations.V34.Attachments namespace Spine.Implementations.SpineWrappers.V34.Attachments
{ {
internal sealed class RegionAttachment34(RegionAttachment innerObject) : internal sealed class RegionAttachment34(RegionAttachment innerObject) :
Attachment34(innerObject), Attachment34(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V34.Attachments
public override RegionAttachment InnerObject => _o; public override RegionAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot34 st) if (slot is Slot34 st)
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime34; using SpineRuntime34;
namespace Spine.Implementations.V34 namespace Spine.Implementations.SpineWrappers.V34
{ {
internal sealed class Bone34(Bone innerObject, Bone34? parent = null) : IBone internal sealed class Bone34(Bone innerObject, Bone34? parent = null) : IBone
{ {

View File

@@ -5,10 +5,10 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Frozen; using System.Collections.Frozen;
using System.Collections.Immutable; using System.Collections.Immutable;
using Spine.SpineWrappers;
using SpineRuntime34; using SpineRuntime34;
using Spine.Interfaces;
namespace Spine.Implementations.V34 namespace Spine.Implementations.SpineWrappers.V34
{ {
internal sealed class Skeleton34 : ISkeleton internal sealed class Skeleton34 : ISkeleton
{ {
@@ -52,7 +52,6 @@ namespace Spine.Implementations.V34
public Skeleton InnerObject => _o; public Skeleton InnerObject => _o;
public string Name => _o.Data.Name;
public float R { get => _o.R; set => _o.R = value; } public float R { get => _o.R; set => _o.R = value; }
public float G { get => _o.G; set => _o.G = value; } public float G { get => _o.G; set => _o.G = value; }
public float B { get => _o.B; set => _o.B = value; } public float B { get => _o.B; set => _o.B = value; }
@@ -96,6 +95,12 @@ namespace Spine.Implementations.V34
public void SetSlotsToSetupPose() => _o.SetSlotsToSetupPose(); public void SetSlotsToSetupPose() => _o.SetSlotsToSetupPose();
public void Update(float delta) => _o.Update(delta); public void Update(float delta) => _o.Update(delta);
public void GetBounds(out float x, out float y, out float w, out float h)
{
float[] _ = [];
_o.GetBounds(out x, out y, out w, out h);
}
public override string ToString() => _o.ToString(); public override string ToString() => _o.ToString();
} }
} }

View File

@@ -1,5 +1,5 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using Spine.Interfaces.Attachments; using Spine.SpineWrappers.Attachments;
using Spine.Utils; using Spine.Utils;
using SpineRuntime34; using SpineRuntime34;
using System; using System;
@@ -8,7 +8,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V34 namespace Spine.Implementations.SpineWrappers.V34
{ {
internal sealed class SkeletonClipping34 : ISkeletonClipping internal sealed class SkeletonClipping34 : ISkeletonClipping
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime34; using SpineRuntime34;
namespace Spine.Implementations.V34 namespace Spine.Implementations.SpineWrappers.V34
{ {
internal sealed class Skin34 : ISkin internal sealed class Skin34 : ISkin
{ {

View File

@@ -5,11 +5,10 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Utils; using Spine.Utils;
using Spine.SpineWrappers;
using SpineRuntime34; using SpineRuntime34;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
namespace Spine.Implementations.V34 namespace Spine.Implementations.SpineWrappers.V34
{ {
internal sealed class Slot34 : ISlot internal sealed class Slot34 : ISlot
{ {
@@ -47,7 +46,7 @@ namespace Spine.Implementations.V34
public float A { get => _o.A; set => _o.A = value; } public float A { get => _o.A; set => _o.A = value; }
public IBone Bone => _bone; public IBone Bone => _bone;
public IAttachment? Attachment public Spine.SpineWrappers.Attachments.IAttachment? Attachment
{ {
get get
{ {

View File

@@ -6,12 +6,12 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Utils; using Spine.Utils;
using Spine.SpineWrappers;
using Spine.SpineWrappers.Attachments;
using SpineRuntime34; using SpineRuntime34;
using Spine.Implementations.V34.Attachments; using Spine.Implementations.SpineWrappers.V34.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
namespace Spine.Implementations.V34 namespace Spine.Implementations.SpineWrappers.V34
{ {
[SpineImplementation(3, 4)] [SpineImplementation(3, 4)]
internal sealed class SpineObjectData34 : SpineObjectData internal sealed class SpineObjectData34 : SpineObjectData
@@ -26,19 +26,12 @@ namespace Spine.Implementations.V34
private readonly ImmutableArray<IAnimation> _animations; private readonly ImmutableArray<IAnimation> _animations;
private readonly FrozenDictionary<string, IAnimation> _animationsByName; private readonly FrozenDictionary<string, IAnimation> _animationsByName;
public SpineObjectData34(string skelPath, string atlasPath, TextureLoader textureLoader) public SpineObjectData34(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader)
: base(skelPath, atlasPath, textureLoader) : base(skelPath, atlasPath, textureLoader)
{ {
// 加载 atlas // 加载 atlas
try try { _atlas = new Atlas(atlasPath, textureLoader); }
{ catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Debug(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
try try
{ {
@@ -48,9 +41,8 @@ namespace Spine.Implementations.V34
{ {
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
} }
catch (Exception ex) catch
{ {
_logger.Debug(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
} }
} }
@@ -60,9 +52,8 @@ namespace Spine.Implementations.V34
{ {
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
} }
catch (Exception ex) catch
{ {
_logger.Debug(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
} }
} }
@@ -70,8 +61,7 @@ namespace Spine.Implementations.V34
catch (Exception ex) catch (Exception ex)
{ {
_atlas.Dispose(); _atlas.Dispose();
_logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
} }
// 加载动画数据 // 加载动画数据

View File

@@ -1,4 +1,4 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime34; using SpineRuntime34;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,7 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V34 namespace Spine.Implementations.SpineWrappers.V34
{ {
internal sealed class TrackEntry34(TrackEntry innerObject, AnimationState34 animationState, SpineObjectData34 data): ITrackEntry internal sealed class TrackEntry34(TrackEntry innerObject, AnimationState34 animationState, SpineObjectData34 data): ITrackEntry
{ {
@@ -34,7 +34,7 @@ namespace Spine.Implementations.V34
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Start += f; _o.Start += f;
@@ -63,7 +63,7 @@ namespace Spine.Implementations.V34
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.End += f; _o.End += f;
@@ -92,7 +92,7 @@ namespace Spine.Implementations.V34
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Complete += f; _o.Complete += f;

View File

@@ -1,4 +1,4 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime35; using SpineRuntime35;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,7 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V35 namespace Spine.Implementations.SpineWrappers.V35
{ {
internal sealed class Animation35(Animation innerObject) : IAnimation internal sealed class Animation35(Animation innerObject) : IAnimation
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime35; using SpineRuntime35;
namespace Spine.Implementations.V35 namespace Spine.Implementations.SpineWrappers.V35
{ {
internal sealed class AnimationState35(AnimationState innerObject, SpineObjectData35 data) : IAnimationState internal sealed class AnimationState35(AnimationState innerObject, SpineObjectData35 data) : IAnimationState
{ {
@@ -27,7 +27,7 @@ namespace Spine.Implementations.V35
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Start += f; _o.Start += f;
@@ -56,7 +56,7 @@ namespace Spine.Implementations.V35
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Interrupt += f; _o.Interrupt += f;
@@ -85,7 +85,7 @@ namespace Spine.Implementations.V35
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.End += f; _o.End += f;
@@ -114,7 +114,7 @@ namespace Spine.Implementations.V35
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Complete += f; _o.Complete += f;
@@ -143,7 +143,7 @@ namespace Spine.Implementations.V35
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Dispose += f; _o.Dispose += f;

View File

@@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using Spine.Interfaces.Attachments; using Spine.SpineWrappers.Attachments;
using SpineRuntime35; using SpineRuntime35;
namespace Spine.Implementations.V35.Attachments namespace Spine.Implementations.SpineWrappers.V35.Attachments
{ {
internal abstract class Attachment35(Attachment innerObject) : IAttachment internal abstract class Attachment35(Attachment innerObject) : IAttachment
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V35; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime35; using SpineRuntime35;
namespace Spine.Implementations.V35.Attachments namespace Spine.Implementations.SpineWrappers.V35.Attachments
{ {
internal sealed class BoundingBoxAttachment35(BoundingBoxAttachment innerObject) : internal sealed class BoundingBoxAttachment35(BoundingBoxAttachment innerObject) :
Attachment35(innerObject), Attachment35(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V35.Attachments
public override BoundingBoxAttachment InnerObject => _o; public override BoundingBoxAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot35 st) if (slot is Slot35 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V35; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime35; using SpineRuntime35;
namespace Spine.Implementations.V35.Attachments namespace Spine.Implementations.SpineWrappers.V35.Attachments
{ {
internal sealed class ClippingAttachment35(ClippingAttachment innerObject) : internal sealed class ClippingAttachment35(ClippingAttachment innerObject) :
Attachment35(innerObject), Attachment35(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V35.Attachments
public override ClippingAttachment InnerObject => _o; public override ClippingAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot35 st) if (slot is Slot35 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V35; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime35; using SpineRuntime35;
namespace Spine.Implementations.V35.Attachments namespace Spine.Implementations.SpineWrappers.V35.Attachments
{ {
internal sealed class MeshAttachment35(MeshAttachment innerObject) : internal sealed class MeshAttachment35(MeshAttachment innerObject) :
Attachment35(innerObject), Attachment35(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V35.Attachments
public override MeshAttachment InnerObject => _o; public override MeshAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot35 st) if (slot is Slot35 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V35; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime35; using SpineRuntime35;
namespace Spine.Implementations.V35.Attachments namespace Spine.Implementations.SpineWrappers.V35.Attachments
{ {
internal sealed class PathAttachment35(PathAttachment innerObject) : internal sealed class PathAttachment35(PathAttachment innerObject) :
Attachment35(innerObject), Attachment35(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V35.Attachments
public override PathAttachment InnerObject => _o; public override PathAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot35 st) if (slot is Slot35 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V35; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime35; using SpineRuntime35;
namespace Spine.Implementations.V35.Attachments namespace Spine.Implementations.SpineWrappers.V35.Attachments
{ {
internal sealed class PointAttachment35(PointAttachment innerObject) : internal sealed class PointAttachment35(PointAttachment innerObject) :
Attachment35(innerObject), Attachment35(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V35.Attachments
public override PointAttachment InnerObject => _o; public override PointAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot35 st) if (slot is Slot35 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V35; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime35; using SpineRuntime35;
namespace Spine.Implementations.V35.Attachments namespace Spine.Implementations.SpineWrappers.V35.Attachments
{ {
internal sealed class RegionAttachment35(RegionAttachment innerObject) : internal sealed class RegionAttachment35(RegionAttachment innerObject) :
Attachment35(innerObject), Attachment35(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V35.Attachments
public override RegionAttachment InnerObject => _o; public override RegionAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot35 st) if (slot is Slot35 st)
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime35; using SpineRuntime35;
namespace Spine.Implementations.V35 namespace Spine.Implementations.SpineWrappers.V35
{ {
internal sealed class Bone35(Bone innerObject, Bone35? parent = null) : IBone internal sealed class Bone35(Bone innerObject, Bone35? parent = null) : IBone
{ {

View File

@@ -5,10 +5,10 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Frozen; using System.Collections.Frozen;
using System.Collections.Immutable; using System.Collections.Immutable;
using Spine.SpineWrappers;
using SpineRuntime35; using SpineRuntime35;
using Spine.Interfaces;
namespace Spine.Implementations.V35 namespace Spine.Implementations.SpineWrappers.V35
{ {
internal sealed class Skeleton35 : ISkeleton internal sealed class Skeleton35 : ISkeleton
{ {
@@ -52,7 +52,6 @@ namespace Spine.Implementations.V35
public Skeleton InnerObject => _o; public Skeleton InnerObject => _o;
public string Name => _o.Data.Name;
public float R { get => _o.R; set => _o.R = value; } public float R { get => _o.R; set => _o.R = value; }
public float G { get => _o.G; set => _o.G = value; } public float G { get => _o.G; set => _o.G = value; }
public float B { get => _o.B; set => _o.B = value; } public float B { get => _o.B; set => _o.B = value; }
@@ -96,6 +95,12 @@ namespace Spine.Implementations.V35
public void SetSlotsToSetupPose() => _o.SetSlotsToSetupPose(); public void SetSlotsToSetupPose() => _o.SetSlotsToSetupPose();
public void Update(float delta) => _o.Update(delta); public void Update(float delta) => _o.Update(delta);
public void GetBounds(out float x, out float y, out float w, out float h)
{
float[] _ = [];
_o.GetBounds(out x, out y, out w, out h, ref _);
}
public override string ToString() => _o.ToString(); public override string ToString() => _o.ToString();
} }
} }

View File

@@ -1,5 +1,5 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using Spine.Interfaces.Attachments; using Spine.SpineWrappers.Attachments;
using Spine.Utils; using Spine.Utils;
using SpineRuntime35; using SpineRuntime35;
using System; using System;
@@ -8,7 +8,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V35 namespace Spine.Implementations.SpineWrappers.V35
{ {
internal sealed class SkeletonClipping35 : ISkeletonClipping internal sealed class SkeletonClipping35 : ISkeletonClipping
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime35; using SpineRuntime35;
namespace Spine.Implementations.V35 namespace Spine.Implementations.SpineWrappers.V35
{ {
internal sealed class Skin35 : ISkin internal sealed class Skin35 : ISkin
{ {

View File

@@ -5,11 +5,10 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Utils; using Spine.Utils;
using Spine.SpineWrappers;
using SpineRuntime35; using SpineRuntime35;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
namespace Spine.Implementations.V35 namespace Spine.Implementations.SpineWrappers.V35
{ {
internal sealed class Slot35 : ISlot internal sealed class Slot35 : ISlot
{ {
@@ -47,7 +46,7 @@ namespace Spine.Implementations.V35
public float A { get => _o.A; set => _o.A = value; } public float A { get => _o.A; set => _o.A = value; }
public IBone Bone => _bone; public IBone Bone => _bone;
public IAttachment? Attachment public Spine.SpineWrappers.Attachments.IAttachment? Attachment
{ {
get get
{ {

View File

@@ -6,12 +6,12 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Utils; using Spine.Utils;
using Spine.SpineWrappers;
using Spine.SpineWrappers.Attachments;
using SpineRuntime35; using SpineRuntime35;
using Spine.Implementations.V35.Attachments; using Spine.Implementations.SpineWrappers.V35.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
namespace Spine.Implementations.V35 namespace Spine.Implementations.SpineWrappers.V35
{ {
[SpineImplementation(3, 5)] [SpineImplementation(3, 5)]
internal sealed class SpineObjectData35 : SpineObjectData internal sealed class SpineObjectData35 : SpineObjectData
@@ -26,19 +26,12 @@ namespace Spine.Implementations.V35
private readonly ImmutableArray<IAnimation> _animations; private readonly ImmutableArray<IAnimation> _animations;
private readonly FrozenDictionary<string, IAnimation> _animationsByName; private readonly FrozenDictionary<string, IAnimation> _animationsByName;
public SpineObjectData35(string skelPath, string atlasPath, TextureLoader textureLoader) public SpineObjectData35(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader)
: base(skelPath, atlasPath, textureLoader) : base(skelPath, atlasPath, textureLoader)
{ {
// 加载 atlas // 加载 atlas
try try { _atlas = new Atlas(atlasPath, textureLoader); }
{ catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Debug(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
try try
{ {
@@ -48,9 +41,8 @@ namespace Spine.Implementations.V35
{ {
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
} }
catch (Exception ex) catch
{ {
_logger.Debug(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
} }
} }
@@ -60,9 +52,8 @@ namespace Spine.Implementations.V35
{ {
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
} }
catch (Exception ex) catch
{ {
_logger.Debug(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
} }
} }
@@ -70,8 +61,7 @@ namespace Spine.Implementations.V35
catch (Exception ex) catch (Exception ex)
{ {
_atlas.Dispose(); _atlas.Dispose();
_logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
} }
// 加载动画数据 // 加载动画数据

View File

@@ -1,4 +1,4 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime35; using SpineRuntime35;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,7 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V35 namespace Spine.Implementations.SpineWrappers.V35
{ {
internal sealed class TrackEntry35(TrackEntry innerObject, AnimationState35 animationState, SpineObjectData35 data): ITrackEntry internal sealed class TrackEntry35(TrackEntry innerObject, AnimationState35 animationState, SpineObjectData35 data): ITrackEntry
{ {
@@ -26,7 +26,7 @@ namespace Spine.Implementations.V35
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Start += f; _o.Start += f;
@@ -55,7 +55,7 @@ namespace Spine.Implementations.V35
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Interrupt += f; _o.Interrupt += f;
@@ -84,7 +84,7 @@ namespace Spine.Implementations.V35
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.End += f; _o.End += f;
@@ -113,7 +113,7 @@ namespace Spine.Implementations.V35
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Complete += f; _o.Complete += f;
@@ -142,7 +142,7 @@ namespace Spine.Implementations.V35
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Dispose += f; _o.Dispose += f;

View File

@@ -1,4 +1,4 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime36; using SpineRuntime36;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,7 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V36 namespace Spine.Implementations.SpineWrappers.V36
{ {
internal sealed class Animation36(Animation innerObject) : IAnimation internal sealed class Animation36(Animation innerObject) : IAnimation
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime36; using SpineRuntime36;
namespace Spine.Implementations.V36 namespace Spine.Implementations.SpineWrappers.V36
{ {
internal sealed class AnimationState36(AnimationState innerObject, SpineObjectData36 data) : IAnimationState internal sealed class AnimationState36(AnimationState innerObject, SpineObjectData36 data) : IAnimationState
{ {
@@ -27,7 +27,7 @@ namespace Spine.Implementations.V36
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Start += f; _o.Start += f;
@@ -56,7 +56,7 @@ namespace Spine.Implementations.V36
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Interrupt += f; _o.Interrupt += f;
@@ -85,7 +85,7 @@ namespace Spine.Implementations.V36
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.End += f; _o.End += f;
@@ -114,7 +114,7 @@ namespace Spine.Implementations.V36
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Complete += f; _o.Complete += f;
@@ -143,7 +143,7 @@ namespace Spine.Implementations.V36
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Dispose += f; _o.Dispose += f;

View File

@@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using Spine.Interfaces.Attachments; using Spine.SpineWrappers.Attachments;
using SpineRuntime36; using SpineRuntime36;
namespace Spine.Implementations.V36.Attachments namespace Spine.Implementations.SpineWrappers.V36.Attachments
{ {
internal abstract class Attachment36(Attachment innerObject) : IAttachment internal abstract class Attachment36(Attachment innerObject) : IAttachment
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V36; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime36; using SpineRuntime36;
namespace Spine.Implementations.V36.Attachments namespace Spine.Implementations.SpineWrappers.V36.Attachments
{ {
internal sealed class BoundingBoxAttachment36(BoundingBoxAttachment innerObject) : internal sealed class BoundingBoxAttachment36(BoundingBoxAttachment innerObject) :
Attachment36(innerObject), Attachment36(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V36.Attachments
public override BoundingBoxAttachment InnerObject => _o; public override BoundingBoxAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot36 st) if (slot is Slot36 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V36; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime36; using SpineRuntime36;
namespace Spine.Implementations.V36.Attachments namespace Spine.Implementations.SpineWrappers.V36.Attachments
{ {
internal sealed class ClippingAttachment36(ClippingAttachment innerObject) : internal sealed class ClippingAttachment36(ClippingAttachment innerObject) :
Attachment36(innerObject), Attachment36(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V36.Attachments
public override ClippingAttachment InnerObject => _o; public override ClippingAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot36 st) if (slot is Slot36 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V36; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime36; using SpineRuntime36;
namespace Spine.Implementations.V36.Attachments namespace Spine.Implementations.SpineWrappers.V36.Attachments
{ {
internal sealed class MeshAttachment36(MeshAttachment innerObject) : internal sealed class MeshAttachment36(MeshAttachment innerObject) :
Attachment36(innerObject), Attachment36(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V36.Attachments
public override MeshAttachment InnerObject => _o; public override MeshAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot36 st) if (slot is Slot36 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V36; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime36; using SpineRuntime36;
namespace Spine.Implementations.V36.Attachments namespace Spine.Implementations.SpineWrappers.V36.Attachments
{ {
internal sealed class PathAttachment36(PathAttachment innerObject) : internal sealed class PathAttachment36(PathAttachment innerObject) :
Attachment36(innerObject), Attachment36(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V36.Attachments
public override PathAttachment InnerObject => _o; public override PathAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot36 st) if (slot is Slot36 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V36; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime36; using SpineRuntime36;
namespace Spine.Implementations.V36.Attachments namespace Spine.Implementations.SpineWrappers.V36.Attachments
{ {
internal sealed class PointAttachment36(PointAttachment innerObject) : internal sealed class PointAttachment36(PointAttachment innerObject) :
Attachment36(innerObject), Attachment36(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V36.Attachments
public override PointAttachment InnerObject => _o; public override PointAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot36 st) if (slot is Slot36 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V36; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime36; using SpineRuntime36;
namespace Spine.Implementations.V36.Attachments namespace Spine.Implementations.SpineWrappers.V36.Attachments
{ {
internal sealed class RegionAttachment36(RegionAttachment innerObject) : internal sealed class RegionAttachment36(RegionAttachment innerObject) :
Attachment36(innerObject), Attachment36(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V36.Attachments
public override RegionAttachment InnerObject => _o; public override RegionAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot36 st) if (slot is Slot36 st)
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime36; using SpineRuntime36;
namespace Spine.Implementations.V36 namespace Spine.Implementations.SpineWrappers.V36
{ {
internal sealed class Bone36(Bone innerObject, Bone36? parent = null) : IBone internal sealed class Bone36(Bone innerObject, Bone36? parent = null) : IBone
{ {

View File

@@ -5,10 +5,10 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Frozen; using System.Collections.Frozen;
using System.Collections.Immutable; using System.Collections.Immutable;
using Spine.SpineWrappers;
using SpineRuntime36; using SpineRuntime36;
using Spine.Interfaces;
namespace Spine.Implementations.V36 namespace Spine.Implementations.SpineWrappers.V36
{ {
internal sealed class Skeleton36 : ISkeleton internal sealed class Skeleton36 : ISkeleton
{ {
@@ -52,7 +52,6 @@ namespace Spine.Implementations.V36
public Skeleton InnerObject => _o; public Skeleton InnerObject => _o;
public string Name => _o.Data.Name;
public float R { get => _o.R; set => _o.R = value; } public float R { get => _o.R; set => _o.R = value; }
public float G { get => _o.G; set => _o.G = value; } public float G { get => _o.G; set => _o.G = value; }
public float B { get => _o.B; set => _o.B = value; } public float B { get => _o.B; set => _o.B = value; }
@@ -96,6 +95,12 @@ namespace Spine.Implementations.V36
public void SetSlotsToSetupPose() => _o.SetSlotsToSetupPose(); public void SetSlotsToSetupPose() => _o.SetSlotsToSetupPose();
public void Update(float delta) => _o.Update(delta); public void Update(float delta) => _o.Update(delta);
public void GetBounds(out float x, out float y, out float w, out float h)
{
float[] _ = [];
_o.GetBounds(out x, out y, out w, out h, ref _);
}
public override string ToString() => _o.ToString(); public override string ToString() => _o.ToString();
} }
} }

View File

@@ -1,5 +1,5 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using Spine.Interfaces.Attachments; using Spine.SpineWrappers.Attachments;
using Spine.Utils; using Spine.Utils;
using SpineRuntime36; using SpineRuntime36;
using System; using System;
@@ -8,7 +8,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V36 namespace Spine.Implementations.SpineWrappers.V36
{ {
internal sealed class SkeletonClipping36 : ISkeletonClipping internal sealed class SkeletonClipping36 : ISkeletonClipping
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime36; using SpineRuntime36;
namespace Spine.Implementations.V36 namespace Spine.Implementations.SpineWrappers.V36
{ {
internal sealed class Skin36 : ISkin internal sealed class Skin36 : ISkin
{ {

View File

@@ -5,11 +5,10 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Utils; using Spine.Utils;
using Spine.SpineWrappers;
using SpineRuntime36; using SpineRuntime36;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
namespace Spine.Implementations.V36 namespace Spine.Implementations.SpineWrappers.V36
{ {
internal sealed class Slot36 : ISlot internal sealed class Slot36 : ISlot
{ {
@@ -47,7 +46,7 @@ namespace Spine.Implementations.V36
public float A { get => _o.A; set => _o.A = value; } public float A { get => _o.A; set => _o.A = value; }
public IBone Bone => _bone; public IBone Bone => _bone;
public IAttachment? Attachment public Spine.SpineWrappers.Attachments.IAttachment? Attachment
{ {
get get
{ {

View File

@@ -6,12 +6,12 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Utils; using Spine.Utils;
using Spine.SpineWrappers;
using Spine.SpineWrappers.Attachments;
using SpineRuntime36; using SpineRuntime36;
using Spine.Implementations.V36.Attachments; using Spine.Implementations.SpineWrappers.V36.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
namespace Spine.Implementations.V36 namespace Spine.Implementations.SpineWrappers.V36
{ {
[SpineImplementation(3, 6)] [SpineImplementation(3, 6)]
internal sealed class SpineObjectData36 : SpineObjectData internal sealed class SpineObjectData36 : SpineObjectData
@@ -26,19 +26,12 @@ namespace Spine.Implementations.V36
private readonly ImmutableArray<IAnimation> _animations; private readonly ImmutableArray<IAnimation> _animations;
private readonly FrozenDictionary<string, IAnimation> _animationsByName; private readonly FrozenDictionary<string, IAnimation> _animationsByName;
public SpineObjectData36(string skelPath, string atlasPath, TextureLoader textureLoader) public SpineObjectData36(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader)
: base(skelPath, atlasPath, textureLoader) : base(skelPath, atlasPath, textureLoader)
{ {
// 加载 atlas // 加载 atlas
try try { _atlas = new Atlas(atlasPath, textureLoader); }
{ catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Debug(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
try try
{ {
@@ -48,9 +41,8 @@ namespace Spine.Implementations.V36
{ {
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
} }
catch (Exception ex) catch
{ {
_logger.Debug(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
} }
} }
@@ -60,9 +52,8 @@ namespace Spine.Implementations.V36
{ {
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
} }
catch (Exception ex) catch
{ {
_logger.Debug(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
} }
} }
@@ -70,8 +61,7 @@ namespace Spine.Implementations.V36
catch (Exception ex) catch (Exception ex)
{ {
_atlas.Dispose(); _atlas.Dispose();
_logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
} }
// 加载动画数据 // 加载动画数据

View File

@@ -1,4 +1,4 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime36; using SpineRuntime36;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,7 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V36 namespace Spine.Implementations.SpineWrappers.V36
{ {
internal sealed class TrackEntry36(TrackEntry innerObject, AnimationState36 animationState, SpineObjectData36 data): ITrackEntry internal sealed class TrackEntry36(TrackEntry innerObject, AnimationState36 animationState, SpineObjectData36 data): ITrackEntry
{ {
@@ -26,7 +26,7 @@ namespace Spine.Implementations.V36
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Start += f; _o.Start += f;
@@ -55,7 +55,7 @@ namespace Spine.Implementations.V36
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Interrupt += f; _o.Interrupt += f;
@@ -84,7 +84,7 @@ namespace Spine.Implementations.V36
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.End += f; _o.End += f;
@@ -113,7 +113,7 @@ namespace Spine.Implementations.V36
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Complete += f; _o.Complete += f;
@@ -142,7 +142,7 @@ namespace Spine.Implementations.V36
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Dispose += f; _o.Dispose += f;

View File

@@ -1,4 +1,4 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime37; using SpineRuntime37;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,7 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V37 namespace Spine.Implementations.SpineWrappers.V37
{ {
internal sealed class Animation37(Animation innerObject) : IAnimation internal sealed class Animation37(Animation innerObject) : IAnimation
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime37; using SpineRuntime37;
namespace Spine.Implementations.V37 namespace Spine.Implementations.SpineWrappers.V37
{ {
internal sealed class AnimationState37(AnimationState innerObject, SpineObjectData37 data) : IAnimationState internal sealed class AnimationState37(AnimationState innerObject, SpineObjectData37 data) : IAnimationState
{ {
@@ -27,7 +27,7 @@ namespace Spine.Implementations.V37
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Start += f; _o.Start += f;
@@ -56,7 +56,7 @@ namespace Spine.Implementations.V37
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Interrupt += f; _o.Interrupt += f;
@@ -85,7 +85,7 @@ namespace Spine.Implementations.V37
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.End += f; _o.End += f;
@@ -114,7 +114,7 @@ namespace Spine.Implementations.V37
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Complete += f; _o.Complete += f;
@@ -143,7 +143,7 @@ namespace Spine.Implementations.V37
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Dispose += f; _o.Dispose += f;

View File

@@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using Spine.Interfaces.Attachments; using Spine.SpineWrappers.Attachments;
using SpineRuntime37; using SpineRuntime37;
namespace Spine.Implementations.V37.Attachments namespace Spine.Implementations.SpineWrappers.V37.Attachments
{ {
internal abstract class Attachment37(Attachment innerObject) : IAttachment internal abstract class Attachment37(Attachment innerObject) : IAttachment
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V37; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime37; using SpineRuntime37;
namespace Spine.Implementations.V37.Attachments namespace Spine.Implementations.SpineWrappers.V37.Attachments
{ {
internal sealed class BoundingBoxAttachment37(BoundingBoxAttachment innerObject) : internal sealed class BoundingBoxAttachment37(BoundingBoxAttachment innerObject) :
Attachment37(innerObject), Attachment37(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V37.Attachments
public override BoundingBoxAttachment InnerObject => _o; public override BoundingBoxAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot37 st) if (slot is Slot37 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V37; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime37; using SpineRuntime37;
namespace Spine.Implementations.V37.Attachments namespace Spine.Implementations.SpineWrappers.V37.Attachments
{ {
internal sealed class ClippingAttachment37(ClippingAttachment innerObject) : internal sealed class ClippingAttachment37(ClippingAttachment innerObject) :
Attachment37(innerObject), Attachment37(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V37.Attachments
public override ClippingAttachment InnerObject => _o; public override ClippingAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot37 st) if (slot is Slot37 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V37; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime37; using SpineRuntime37;
namespace Spine.Implementations.V37.Attachments namespace Spine.Implementations.SpineWrappers.V37.Attachments
{ {
internal sealed class MeshAttachment37(MeshAttachment innerObject) : internal sealed class MeshAttachment37(MeshAttachment innerObject) :
Attachment37(innerObject), Attachment37(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V37.Attachments
public override MeshAttachment InnerObject => _o; public override MeshAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot37 st) if (slot is Slot37 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V37; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime37; using SpineRuntime37;
namespace Spine.Implementations.V37.Attachments namespace Spine.Implementations.SpineWrappers.V37.Attachments
{ {
internal sealed class PathAttachment37(PathAttachment innerObject) : internal sealed class PathAttachment37(PathAttachment innerObject) :
Attachment37(innerObject), Attachment37(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V37.Attachments
public override PathAttachment InnerObject => _o; public override PathAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot37 st) if (slot is Slot37 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V37; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime37; using SpineRuntime37;
namespace Spine.Implementations.V37.Attachments namespace Spine.Implementations.SpineWrappers.V37.Attachments
{ {
internal sealed class PointAttachment37(PointAttachment innerObject) : internal sealed class PointAttachment37(PointAttachment innerObject) :
Attachment37(innerObject), Attachment37(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V37.Attachments
public override PointAttachment InnerObject => _o; public override PointAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot37 st) if (slot is Slot37 st)
{ {

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V37; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime37; using SpineRuntime37;
namespace Spine.Implementations.V37.Attachments namespace Spine.Implementations.SpineWrappers.V37.Attachments
{ {
internal sealed class RegionAttachment37(RegionAttachment innerObject) : internal sealed class RegionAttachment37(RegionAttachment innerObject) :
Attachment37(innerObject), Attachment37(innerObject),
@@ -18,7 +16,7 @@ namespace Spine.Implementations.V37.Attachments
public override RegionAttachment InnerObject => _o; public override RegionAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot37 st) if (slot is Slot37 st)
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime37; using SpineRuntime37;
namespace Spine.Implementations.V37 namespace Spine.Implementations.SpineWrappers.V37
{ {
internal sealed class Bone37(Bone innerObject, Bone37? parent = null) : IBone internal sealed class Bone37(Bone innerObject, Bone37? parent = null) : IBone
{ {

View File

@@ -5,10 +5,10 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Frozen; using System.Collections.Frozen;
using System.Collections.Immutable; using System.Collections.Immutable;
using Spine.SpineWrappers;
using SpineRuntime37; using SpineRuntime37;
using Spine.Interfaces;
namespace Spine.Implementations.V37 namespace Spine.Implementations.SpineWrappers.V37
{ {
internal sealed class Skeleton37 : ISkeleton internal sealed class Skeleton37 : ISkeleton
{ {
@@ -52,7 +52,6 @@ namespace Spine.Implementations.V37
public Skeleton InnerObject => _o; public Skeleton InnerObject => _o;
public string Name => _o.Data.Name;
public float R { get => _o.R; set => _o.R = value; } public float R { get => _o.R; set => _o.R = value; }
public float G { get => _o.G; set => _o.G = value; } public float G { get => _o.G; set => _o.G = value; }
public float B { get => _o.B; set => _o.B = value; } public float B { get => _o.B; set => _o.B = value; }
@@ -96,6 +95,12 @@ namespace Spine.Implementations.V37
public void SetSlotsToSetupPose() => _o.SetSlotsToSetupPose(); public void SetSlotsToSetupPose() => _o.SetSlotsToSetupPose();
public void Update(float delta) => _o.Update(delta); public void Update(float delta) => _o.Update(delta);
public void GetBounds(out float x, out float y, out float w, out float h)
{
float[] _ = [];
_o.GetBounds(out x, out y, out w, out h, ref _);
}
public override string ToString() => _o.ToString(); public override string ToString() => _o.ToString();
} }
} }

View File

@@ -1,5 +1,5 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using Spine.Interfaces.Attachments; using Spine.SpineWrappers.Attachments;
using Spine.Utils; using Spine.Utils;
using SpineRuntime37; using SpineRuntime37;
using System; using System;
@@ -8,7 +8,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V37 namespace Spine.Implementations.SpineWrappers.V37
{ {
internal sealed class SkeletonClipping37 : ISkeletonClipping internal sealed class SkeletonClipping37 : ISkeletonClipping
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime37; using SpineRuntime37;
namespace Spine.Implementations.V37 namespace Spine.Implementations.SpineWrappers.V37
{ {
internal sealed class Skin37 : ISkin internal sealed class Skin37 : ISkin
{ {

View File

@@ -5,11 +5,10 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Utils; using Spine.Utils;
using Spine.SpineWrappers;
using SpineRuntime37; using SpineRuntime37;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
namespace Spine.Implementations.V37 namespace Spine.Implementations.SpineWrappers.V37
{ {
internal sealed class Slot37 : ISlot internal sealed class Slot37 : ISlot
{ {
@@ -47,7 +46,7 @@ namespace Spine.Implementations.V37
public float A { get => _o.A; set => _o.A = value; } public float A { get => _o.A; set => _o.A = value; }
public IBone Bone => _bone; public IBone Bone => _bone;
public IAttachment? Attachment public Spine.SpineWrappers.Attachments.IAttachment? Attachment
{ {
get get
{ {

View File

@@ -6,12 +6,12 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Utils; using Spine.Utils;
using Spine.SpineWrappers;
using Spine.SpineWrappers.Attachments;
using SpineRuntime37; using SpineRuntime37;
using Spine.Implementations.V37.Attachments; using Spine.Implementations.SpineWrappers.V37.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
namespace Spine.Implementations.V37 namespace Spine.Implementations.SpineWrappers.V37
{ {
[SpineImplementation(3, 7)] [SpineImplementation(3, 7)]
internal sealed class SpineObjectData37 : SpineObjectData internal sealed class SpineObjectData37 : SpineObjectData
@@ -26,19 +26,12 @@ namespace Spine.Implementations.V37
private readonly ImmutableArray<IAnimation> _animations; private readonly ImmutableArray<IAnimation> _animations;
private readonly FrozenDictionary<string, IAnimation> _animationsByName; private readonly FrozenDictionary<string, IAnimation> _animationsByName;
public SpineObjectData37(string skelPath, string atlasPath, TextureLoader textureLoader) public SpineObjectData37(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader)
: base(skelPath, atlasPath, textureLoader) : base(skelPath, atlasPath, textureLoader)
{ {
// 加载 atlas // 加载 atlas
try try { _atlas = new Atlas(atlasPath, textureLoader); }
{ catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Debug(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
try try
{ {
@@ -48,9 +41,8 @@ namespace Spine.Implementations.V37
{ {
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
} }
catch (Exception ex) catch
{ {
_logger.Debug(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
} }
} }
@@ -60,9 +52,8 @@ namespace Spine.Implementations.V37
{ {
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
} }
catch (Exception ex) catch
{ {
_logger.Debug(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
} }
} }
@@ -70,8 +61,7 @@ namespace Spine.Implementations.V37
catch (Exception ex) catch (Exception ex)
{ {
_atlas.Dispose(); _atlas.Dispose();
_logger.Debug(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
} }
// 加载动画数据 // 加载动画数据

View File

@@ -1,4 +1,4 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime37; using SpineRuntime37;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,7 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V37 namespace Spine.Implementations.SpineWrappers.V37
{ {
internal sealed class TrackEntry37(TrackEntry innerObject, AnimationState37 animationState, SpineObjectData37 data): ITrackEntry internal sealed class TrackEntry37(TrackEntry innerObject, AnimationState37 animationState, SpineObjectData37 data): ITrackEntry
{ {
@@ -26,7 +26,7 @@ namespace Spine.Implementations.V37
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Start += f; _o.Start += f;
@@ -55,7 +55,7 @@ namespace Spine.Implementations.V37
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Interrupt += f; _o.Interrupt += f;
@@ -84,7 +84,7 @@ namespace Spine.Implementations.V37
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.End += f; _o.End += f;
@@ -113,7 +113,7 @@ namespace Spine.Implementations.V37
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Complete += f; _o.Complete += f;
@@ -142,7 +142,7 @@ namespace Spine.Implementations.V37
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(_animationState.GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(_animationState.GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Dispose += f; _o.Dispose += f;

View File

@@ -1,4 +1,4 @@
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime38; using SpineRuntime38;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,7 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Implementations.V38 namespace Spine.Implementations.SpineWrappers.V38
{ {
internal sealed class Animation38(Animation innerObject) : IAnimation internal sealed class Animation38(Animation innerObject) : IAnimation
{ {

View File

@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using SpineRuntime38; using SpineRuntime38;
namespace Spine.Implementations.V38 namespace Spine.Implementations.SpineWrappers.V38
{ {
internal sealed class AnimationState38(AnimationState innerObject, SpineObjectData38 data) : IAnimationState internal sealed class AnimationState38(AnimationState innerObject, SpineObjectData38 data) : IAnimationState
{ {
@@ -27,7 +27,7 @@ namespace Spine.Implementations.V38
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Start += f; _o.Start += f;
@@ -56,7 +56,7 @@ namespace Spine.Implementations.V38
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Interrupt += f; _o.Interrupt += f;
@@ -85,7 +85,7 @@ namespace Spine.Implementations.V38
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.End += f; _o.End += f;
@@ -114,7 +114,7 @@ namespace Spine.Implementations.V38
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Complete += f; _o.Complete += f;
@@ -143,7 +143,7 @@ namespace Spine.Implementations.V38
if (value is null) return; if (value is null) return;
if (!_eventMapping.TryGetValue(value, out var f)) if (!_eventMapping.TryGetValue(value, out var f))
{ {
_eventMapping[value] = f = (t) => value(GetTrackEntry(t)); _eventMapping[value] = f = (TrackEntry t) => value(GetTrackEntry(t));
_eventCount[value] = 0; _eventCount[value] = 0;
} }
_o.Dispose += f; _o.Dispose += f;

View File

@@ -3,12 +3,12 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Interfaces; using Spine.SpineWrappers;
using Spine.Interfaces.Attachments; using Spine.SpineWrappers.Attachments;
using SpineRuntime38; using SpineRuntime38;
using SpineRuntime38.Attachments; using SpineRuntime38.Attachments;
namespace Spine.Implementations.V38.Attachments namespace Spine.Implementations.SpineWrappers.V38.Attachments
{ {
internal abstract class Attachment38(Attachment innerObject) : IAttachment internal abstract class Attachment38(Attachment innerObject) : IAttachment
{ {

View File

@@ -3,13 +3,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Spine.Implementations.V38; using Spine.SpineWrappers.Attachments;
using Spine.Interfaces;
using Spine.Interfaces.Attachments;
using SpineRuntime38; using SpineRuntime38;
using SpineRuntime38.Attachments; using SpineRuntime38.Attachments;
namespace Spine.Implementations.V38.Attachments namespace Spine.Implementations.SpineWrappers.V38.Attachments
{ {
internal sealed class BoundingBoxAttachment38(BoundingBoxAttachment innerObject) : internal sealed class BoundingBoxAttachment38(BoundingBoxAttachment innerObject) :
Attachment38(innerObject), Attachment38(innerObject),
@@ -19,7 +17,7 @@ namespace Spine.Implementations.V38.Attachments
public override BoundingBoxAttachment InnerObject => _o; public override BoundingBoxAttachment InnerObject => _o;
public override int ComputeWorldVertices(ISlot slot, ref float[] worldVertices) public override int ComputeWorldVertices(Spine.SpineWrappers.ISlot slot, ref float[] worldVertices)
{ {
if (slot is Slot38 st) if (slot is Slot38 st)
{ {

Some files were not shown because too many files have changed in this diff Show More