// Spine WebGL 运行时在小程序的适配层 // 目标:在不提供 window / document / DOM 事件 的小程序环境里安全使用 spine-webgl。 function getGlobalObject() { if (typeof globalThis !== 'undefined') return globalThis if (typeof global !== 'undefined') return global if (typeof self !== 'undefined') return self return null } /** * 保证全局存在 WebGLRenderingContext 构造器。 * spine 的 ManagedWebGLRenderingContext 构造函数里有: * if (!(canvasOrContext instanceof WebGLRenderingContext || ...)) * 若该标识符未声明会抛 ReferenceError。这里补一个普通函数(instanceof 恒为 false), * 从而稳定进入「把入参当作 canvas、调用 getContext」的分支。 */ function installWebGLShim() { const g = getGlobalObject() if (!g) return false if (typeof g.WebGLRenderingContext === 'undefined') { g.WebGLRenderingContext = function WebGLRenderingContext() {} } return true } /** * 用「假 canvas」包装原生 gl 上下文。 * spine 会调用 canvas.getContext() 并对 canvas 注册 webglcontextlost 事件, * 小程序 canvas 没有 addEventListener,所以这里用空实现顶掉。 */ function wrapGLContext(spineWebgl, gl, width, height) { const canvasLike = { width: width, height: height, getContext: function () { return gl }, addEventListener: function () {}, removeEventListener: function () {}, } return new spineWebgl.ManagedWebGLRenderingContext(canvasLike) } /** * 正交投影 MVP(列主序,WebGL 约定)。 * 把骨骼世界坐标 (x, y) 映射到像素画布:scale 为缩放,tx/ty 为原点在画布上的像素位置。 */ function buildMVP(scale, tx, ty, width, height) { return [ (2 * scale) / width, 0, 0, 0, 0, (2 * scale) / height, 0, 0, 0, 0, -1, 0, (2 * tx) / width - 1, (2 * ty) / height - 1, 0, 1, ] } function baseName(p) { const s = String(p || '') const i = Math.max(s.lastIndexOf('/'), s.lastIndexOf('\\')) return i >= 0 ? s.slice(i + 1) : s } module.exports = { getGlobalObject, installWebGLShim, wrapGLContext, buildMVP, baseName, }