function readPixelsCommon ( gl , width , height , canvas , opaque ) { const pixels = new Uint8Array ( width * height * 4 ) ; gl . readPixels ( 0 , 0 , width , height , gl . RGBA , gl . UNSIGNED_BYTE , pixels ) ; if ( opaque ) { for ( let i = 3 ; i < pixels . length ; i += 4 ) pixels [ i ] = 0xFF ; } canvas . width = gl . drawingBufferWidth ; canvas . height = gl . drawingBufferHeight ; const ctx = canvas . getContext ( '2d' ) ! ; const img = ctx . createImageData ( width , height ) ; img . data . set ( pixels ) ; ctx . putImageData ( img , 0 , 0 ) ; ctx . save ( ) ; ctx . globalCompositeOperation = 'copy' ; ctx . setTransform ( 1 , 0 , 0 , - 1 , 0 , height ) ; ctx . drawImage ( canvas , 0 , 0 ) ; ctx . restore ( ) ; } export function downloadRenderbufferToCanvas ( gl , renderbuffer , canvas , opaque ) { const fb = gl . createFramebuffer ( ) ; gl . bindFramebuffer ( gl . READ_FRAMEBUFFER , fb ) ; gl . bindRenderbuffer ( gl . RENDERBUFFER , renderbuffer ) ; gl . framebufferRenderbuffer ( gl . READ_FRAMEBUFFER , gl . COLOR_ATTACHMENT0 , gl . RENDERBUFFER , renderbuffer ) ; const width = gl . getRenderbufferParameter ( gl . RENDERBUFFER , gl . RENDERBUFFER_WIDTH ) ; const height = gl . getRenderbufferParameter ( gl . RENDERBUFFER , gl . RENDERBUFFER_HEIGHT ) ; readPixelsCommon ( gl , width , height , canvas , opaque ) ; gl . deleteFramebuffer ( fb ) ; } export function downloadTextureToCanvas ( gl , texture , width , height , canvas , opaque ) { const fb = gl . createFramebuffer ( ) ; gl . bindFramebuffer ( gl . READ_FRAMEBUFFER , fb ) ; gl . framebufferTexture2D ( gl . READ_FRAMEBUFFER , gl . COLOR_ATTACHMENT0 , gl . TEXTURE_2D , texture , 0 ) ; readPixelsCommon ( gl , width , height , canvas , opaque ) ; gl . deleteFramebuffer ( fb ) ; } export function downloadFrontBufferToCanvas ( gl , width , height , canvas , opaque ) { readPixelsCommon ( gl , width , height , canvas , opaque ) ; }