import * as THREE from 'three'; import {prepareExportPixels} from './ExportPixels'; export type ExportKind='photo'|'scene'; /** r169 uses linear shader output for targets; SRGB8_ALPHA8 encodes exactly once. */ export async function captureScenePNG(renderer:THREE.WebGLRenderer,root:Document,kind:ExportKind,signal:AbortSignal,draw:(target:THREE.WebGLRenderTarget)=>void):Promise { const check=()=>{if(signal.aborted)throw new DOMException('Cancelled','AbortError');if(renderer.getContext().isContextLost())throw new Error('화면 연결이 복구된 뒤 다시 저장해 주세요.');}; check(); const source=renderer.getDrawingBufferSize(new THREE.Vector2()); const scale=Math.min(1,(kind==='photo'?1024:2048)/Math.max(source.x,source.y)); const width=Math.max(1,Math.round(source.x*scale)),height=Math.max(1,Math.round(source.y*scale)); const target=new THREE.WebGLRenderTarget(width,height,{type:THREE.UnsignedByteType,format:THREE.RGBAFormat,colorSpace:THREE.SRGBColorSpace,depthBuffer:true,samples:0}); const previous=renderer.getRenderTarget(),viewport=renderer.getViewport(new THREE.Vector4()),scissor=renderer.getScissor(new THREE.Vector4()),scissorTest=renderer.getScissorTest(); const clearColor=renderer.getClearColor(new THREE.Color()),clearAlpha=renderer.getClearAlpha(),autoClear=renderer.autoClear; try { const bytes=new Uint8Array(width*height*4); try { renderer.setClearColor(0x000000,0);renderer.autoClear=true; draw(target); } finally { renderer.setRenderTarget(previous);renderer.setViewport(viewport);renderer.setScissor(scissor);renderer.setScissorTest(scissorTest);renderer.setClearColor(clearColor,clearAlpha);renderer.autoClear=autoClear; } check(); await renderer.readRenderTargetPixelsAsync(target,0,0,width,height,bytes); check(); const pixels=prepareExportPixels(bytes,width,height,kind==='photo'); const canvas=root.createElement('canvas');canvas.width=pixels.width;canvas.height=pixels.height; const context=canvas.getContext('2d');if(!context)throw new Error('이미지를 저장할 수 없어요. 다시 시도해 주세요.'); const output=context.createImageData(pixels.width,pixels.height);output.data.set(pixels.data);context.putImageData(output,0,0); const blob=await new Promise((resolve,reject)=>canvas.toBlob(value=>value?resolve(value):reject(new Error('이미지 파일을 만들지 못했어요.')),'image/png')); check();return blob; } finally {target.dispose();} }