剪切修改

This commit is contained in:
tianmo committed 2026-09-09 15:58:56 +08:00
1 parent 1dcb27ccd9
commit 1b67933cac
5 files changed
+358 -33

No files matched your search

+23 -5
View File
@@ -136,6 +136,9 @@
<input type="range" id="speedRange" min="0" max="3" step="0.05" value="1">
<span id="speedVal">1.0x</span>
</label>
<label title="用于以 Premultiplied Alpha(PMA)方式导出的贴图">
<input type="checkbox" id="pmaCheck"> 预乘
</label>
<div class="spacer"></div>
<button id="thumbBtn" title="使用当前帧生成 400×400 缩略图">🖼 生成缩略图</button>
<label id="verLabel" style="color: var(--text-dim);" title="Spine 版本"></label>
@@ -172,6 +175,7 @@
const fs = require('fs');
const utils = require('../js/spine-utils.js');
const spineBadge = require('../js/spine-badge.js');
const clippingRenderer = require('../js/spine-canvas-clipping.js');
let spineBadgeImagePromise = null;
function loadSpineBadgeImage() {
@@ -232,8 +236,10 @@
// ---------- 全局状态 ----------
let skeleton = null, state = null, stateData = null, skeletonData = null;
let renderer = null;
let activeRuntimeDir = null;
let currentAnim = 0, currentSkin = null;
let playing = true, loop = true, speed = 1;
let premultipliedAlpha = false;
let timeKeeper = null, lastTime = 0, running = false;
let seeking = false; // 用户正在拖动时间轴
let duration = 0; // 当前动画时长
@@ -450,9 +456,9 @@
octx.translate(-cx, -cy);
let offRenderer = renderer;
try {
if (spine.canvas && spine.canvas.SkeletonRenderer) offRenderer = new spine.canvas.SkeletonRenderer(octx);
else if (spine.SkeletonRenderer) offRenderer = new spine.SkeletonRenderer(octx);
offRenderer = clippingRenderer.createRenderer(spine, octx, activeRuntimeDir);
} catch (e) { /* 沿用原 renderer,可能无法正确绑定离屏 ctx */ }
offRenderer.premultipliedAlpha = premultipliedAlpha;
if (offRenderer && 'triangleRendering' in offRenderer) offRenderer.triangleRendering = true;
offRenderer.draw(skeleton);
octx.restore();
@@ -789,6 +795,12 @@
// ---------- 加载资源并与运行时交互 ----------
async function loadAssets() {
// Eagle 只能按 .json 扩展名把文件交给格式扩展。查看器必须再次检查内容,
// 防止普通 JSON 被拿去匹配库中其他 Spine 骨骼资源。
if (utils.extOf(path.basename(filePath)) === '.json' && utils.classifySkeletonJson(filePath) !== 'spine') {
showError('普通 JSON 文件', '该文件不包含 Spine 导出的 skeleton.spine 版本字段,因此不会作为 Spine 骨骼数据加载。');
return;
}
const assets = utils.discoverAssets(filePath);
if (!assets.skeletonPath || !assets.atlasPath) {
@@ -807,6 +819,7 @@
showError('版本不支持', '无法识别的 Spine 版本:' + (version || '未知') + '\n支持的版本:3.6 / 3.7 / 3.8 / 4.0 / 4.1 / 4.2 / 4.3');
return;
}
activeRuntimeDir = runtimeDir;
document.getElementById('verLabel').textContent = 'Spine ' + (version || runtimeDir);
try {
@@ -864,9 +877,8 @@
stateData.defaultMix = 0.2;
state = new spine.AnimationState(stateData);
renderer = (spine.canvas && spine.canvas.SkeletonRenderer) ? new spine.canvas.SkeletonRenderer(ctx) : new spine.SkeletonRenderer(ctx);
// 使用三角渲染,正确处理 mesh 附件(如角色身体的网格)
if (renderer && 'triangleRendering' in renderer) renderer.triangleRendering = true;
renderer = clippingRenderer.createRenderer(spine, ctx, runtimeDir);
renderer.premultipliedAlpha = premultipliedAlpha;
fillAnimations();
fillSkins();
@@ -931,6 +943,12 @@
speed = parseFloat(e.target.value);
document.getElementById('speedVal').textContent = speed.toFixed(2) + 'x';
});
document.getElementById('pmaCheck').addEventListener('change', (e) => {
premultipliedAlpha = e.target.checked;
if (renderer) renderer.premultipliedAlpha = premultipliedAlpha;
draw();
setStatus(premultipliedAlpha ? '已开启预乘 Alpha 渲染' : '已关闭预乘 Alpha 渲染', 1800);
});
document.getElementById('reloadBtn').addEventListener('click', () => {
window.location.reload();
});