Files
erqiwang_youle/client/js/gameabc-framework/spine/SpineOverlayTransform.js
T
2026-08-11 22:17:54 +08:00

89 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================
// SpineOverlayTransform —— WebGL 叠加层坐标标定(纯函数)
//
// 职责:把 gameabc 主画布的权威变换矩阵换算成 WebGL 的 MVP 矩阵。
// 无副作用、无 DOM 依赖,可独立单测。
//
// 为什么不逆向 gameabc.min.js:那是混淆代码(变量名全打乱),读不出它内部如何
// 映射坐标。而 Spine 绘制发生在 gameenddraw(gameabc 绘制流程末尾),此刻 ctx
// 上已带着 gameabc 设好的全局变换 —— 直接向 ctx 要矩阵即可,权威、且 gameabc
// 后续改缩放/响应旋转时自动跟随。
//
// ⚠️ 真机实测确认:Spine 实际画在 gameabc_face.dc.canvas 这张离屏画布上
// (backing 约 1280x720,不在 DOM),gameabc 再把它 blit 到 DOM 中可见的显示
// 画布 #canvas(backing 约 1912x880),最后经 CSS 缩放到屏幕。本函数的
// canvasW/canvasH 必须传绘制缓冲画布(dc.canvas)的 backing 尺寸,因为
// Spine 坐标正是喂给这张画布的,分母须与其同源;叠加层自身的定位/CSS 尺寸/
// drawing buffer 则是另一个来源(显示画布 #canvas),由调用方
// SpineBackendWebGL 负责,不在本函数职责内。
//
// 推导(Spine 世界坐标 Y-up,画布 Y-down):
// 位移由调用方经 skeleton.x = e.x; skeleton.y = -e.y 承担,本矩阵只处理
// scale(1,-1) 与投影,等价于 Canvas 后端的 ctx.translate(e.x,e.y)+ctx.scale(1,-1)。
//
// 1) Spine 世界 → 逻辑坐标: Lx = vx, Ly = -vy
// 2) 逻辑 → 画布像素: Px = a*Lx + c*Ly + e, Py = b*Lx + d*Ly + f
// 3) 画布像素 → NDC: x = 2*Px/W - 1, y = 1 - 2*Py/H
//
// 合并:
// x_ndc = (2a/W)*vx + (-2c/W)*vy + (2e/W - 1)
// y_ndc = (-2b/H)*vx + ( 2d/H)*vy + (1 - 2f/H)
//
// 注意:叠加层 drawing buffer 尺寸在推导中被约掉(gl.viewport 覆盖整个 buffer,
// NDC 自动铺满),故本矩阵只依赖 ctx 变换与绘制缓冲画布 backing 尺寸。因此所有
// entry 共用同一个 MVP,可一次 batcher.begin/end 批量绘制。
// ============================================================
(function(){
var SpineOverlayTransform = {
// ----------------------------------------------------------
// buildMvp(m, canvasW, canvasH, out)
// m : {a,b,c,d,e,f} —— ctx.getTransform() 的六元素
// canvasW : 绘制缓冲画布(gameabc_face.dc.canvas)的 backing 宽(实测约 1280)
// canvasH : 绘制缓冲画布(gameabc_face.dc.canvas)的 backing 高(实测约 720)
// out : 可选,长度 16 的复用数组(避免每帧分配)
// 返回列主序 4x4 矩阵
// ----------------------------------------------------------
buildMvp: function(m, canvasW, canvasH, out) {
var r = out || new Array(16);
var sx = 2 / canvasW;
var sy = 2 / canvasH;
// 第 0 列:vx 的系数
r[0] = sx * m.a;
r[1] = -sy * m.b;
r[2] = 0;
r[3] = 0;
// 第 1 列:vy 的系数
r[4] = -sx * m.c;
r[5] = sy * m.d;
r[6] = 0;
r[7] = 0;
// 第 2 列:z 保持
r[8] = 0;
r[9] = 0;
r[10] = 1;
r[11] = 0;
// 第 3 列:平移
r[12] = sx * m.e - 1;
r[13] = 1 - sy * m.f;
r[14] = 0;
r[15] = 1;
return r;
}
};
if (typeof module !== "undefined" && module.exports) {
module.exports = SpineOverlayTransform;
}
// 友乐运行时有 module 无 require 且共享全局作用域,须无条件暴露全局名
window.SpineOverlayTransform = SpineOverlayTransform;
})();