Files
SpineViewer/tests/build-browser-preview-test.js
T
2026-09-10 18:51:29 +08:00

44 lines
3.8 KiB
JavaScript

'use strict';
const fs=require('fs'),path=require('path'),os=require('os');
const root=path.resolve(__dirname,'..'),fixtures=path.join(__dirname,'.fixtures');
const script=text=>'<script>'+text.replace(/<\/script/gi,'<\\/script')+'</script>';
const versions=['3.4','3.5','3.6','3.7','3.8','4.0','4.1','4.2','4.3'];
const frames=versions.map(version=>{
const dir=path.join(fixtures,version,'spineboy');
const source=path.join(dir,['3.4','3.5'].includes(version)?'spineboy-mesh.skel':'spineboy-pro.skel');
let html=script(`var module={exports:{}};const modules={};function require(n){return modules[n]}const version=${JSON.stringify(version)};`);
for(const name of ['spine-webgl-rasterizer','spine-canvas-clipping','spine-background','spine-legacy-binary'])
html+=script('module={exports:{}};\n'+fs.readFileSync(path.join(root,'js',name+'.js'),'utf8')+`\nmodules['./${name}.js']=module.exports;`);
html+=script(fs.readFileSync(path.join(root,'lib',version,'spine-canvas.js'),'utf8'));
html+=script(`(async()=>{try{
const image=new Image();image.src='data:image/png;base64,${fs.readFileSync(path.join(dir,'spineboy.png')).toString('base64')}';await image.decode();
const text=${JSON.stringify(fs.readFileSync(path.join(dir,'spineboy.atlas'),'utf8'))};
const texture=new (spine.CanvasTexture||spine.canvas.CanvasTexture)(image);let atlas;
if(spine.TextureAtlas.length<=1){atlas=new spine.TextureAtlas(text);for(const page of atlas.pages){if(page.setTexture)page.setTexture(texture);else page.texture=texture}}
else atlas=new spine.TextureAtlas(text,()=>texture);
modules['./spine-legacy-binary.js'].install(spine,version);
const bytes=Uint8Array.from(atob('${fs.readFileSync(source).toString('base64')}'),c=>c.charCodeAt(0));
const data=new spine.SkeletonBinary(new spine.AtlasAttachmentLoader(atlas)).readSkeletonData(bytes),skeleton=new spine.Skeleton(data);
if(spine.Physics)skeleton.updateWorldTransform(spine.Physics.update);else skeleton.updateWorldTransform();
const offset=new spine.Vector2(),size=new spine.Vector2();skeleton.getBounds(offset,size,[]);
const canvas=document.createElement('canvas');canvas.width=canvas.height=400;document.body.appendChild(canvas);
const ctx=canvas.getContext('2d'),renderer=modules['./spine-canvas-clipping.js'].createRenderer(spine,ctx,version);
if(renderer.rasterization!=='webgl')throw Error('WebGL not active');
let normal;
for(const mode of [0,2]){
ctx.setTransform(1,0,0,1,0,0);ctx.fillStyle='#1e1e1e';ctx.fillRect(0,0,400,400);
const scale=320/Math.max(size.x,size.y);ctx.translate(200,200);ctx.scale(scale,-scale);ctx.translate(-offset.x-size.x/2,-offset.y-size.y/2);
modules['./spine-background.js'].drawCheckerboard(ctx,400,400);
for(const slot of skeleton.slots)slot.data.blendMode=mode;
renderer.draw(skeleton);const pixels=ctx.getImageData(0,0,400,400).data;
if(mode===0)normal=pixels;else{let changed=0;for(let i=0;i<pixels.length;i+=4)if(Math.abs(pixels[i]-normal[i])>3)changed++;if(changed<100)throw Error('Slot multiply did not change image');}
}
renderer.premultipliedAlpha=true;renderer.draw(skeleton);renderer.dispose();
parent.postMessage({version,result:'PASS'},'*');
}catch(error){parent.postMessage({version,error:error.stack},'*')}})();`);
return html;
});
const html='<!doctype html><meta charset="utf-8"><style>iframe{width:420px;height:420px;border:0}body{background:#222;color:#eee}</style><pre id="result">RUNNING</pre>'+script(`let results=[];window.addEventListener('message',e=>{if(e.data.version){results.push(e.data);document.getElementById('result').textContent=JSON.stringify(results)}});for(const html of ${JSON.stringify(frames)}){const frame=document.createElement('iframe');frame.srcdoc=html;document.body.appendChild(frame)}`);
const output=path.resolve(process.argv[2]||path.join(os.tmpdir(),'spineviewer-browser-preview-test.html'));
fs.writeFileSync(output,html);console.log(output);