@@ -310,7 +310,9 @@ <h3>Shader Controls</h3>
310310
311311 // Initialize WebGL
312312 const canvas = document . getElementById ( "canvas" )
313- const gl = canvas . getContext ( "webgl" ) || canvas . getContext ( "experimental-webgl" )
313+ const gl =
314+ canvas . getContext ( "webgl" , { preserveDrawingBuffer : true } ) ||
315+ canvas . getContext ( "experimental-webgl" , { preserveDrawingBuffer : true } )
314316
315317 if ( ! gl ) {
316318 alert ( "WebGL not supported" )
@@ -409,6 +411,8 @@ <h3>Shader Controls</h3>
409411
410412 // Animation loop
411413 let startTime = Date . now ( )
414+ let animationId
415+
412416 function render ( ) {
413417 const currentTime = ( Date . now ( ) - startTime ) / 1000
414418
@@ -420,7 +424,7 @@ <h3>Shader Controls</h3>
420424
421425 gl . drawArrays ( gl . TRIANGLE_STRIP , 0 , 4 )
422426
423- requestAnimationFrame ( render )
427+ animationId = requestAnimationFrame ( render )
424428 }
425429
426430 render ( )
@@ -504,16 +508,51 @@ <h3>Shader Controls</h3>
504508
505509 // Screenshot functionality
506510 screenshotBtn . addEventListener ( "click" , ( ) => {
507- canvas . toBlob ( ( blob ) => {
508- const url = URL . createObjectURL ( blob )
509- const a = document . createElement ( "a" )
510- a . href = url
511- a . download = `shader_screenshot_${ new Date ( ) . getTime ( ) } .png`
512- a . click ( )
513- URL . revokeObjectURL ( url )
514- statusDiv . textContent = "Screenshot saved!"
515- setTimeout ( ( ) => ( statusDiv . textContent = "" ) , 3000 )
516- } , "image/png" )
511+ // Force a render before taking screenshot
512+ render ( )
513+
514+ // Use a small delay to ensure the frame is fully rendered
515+ setTimeout ( ( ) => {
516+ // Alternative method: read pixels directly
517+ const width = canvas . width
518+ const height = canvas . height
519+ const pixels = new Uint8Array ( width * height * 4 )
520+
521+ gl . readPixels ( 0 , 0 , width , height , gl . RGBA , gl . UNSIGNED_BYTE , pixels )
522+
523+ // Create a new canvas to draw the pixels (flipped vertically)
524+ const tempCanvas = document . createElement ( "canvas" )
525+ tempCanvas . width = width
526+ tempCanvas . height = height
527+ const tempCtx = tempCanvas . getContext ( "2d" )
528+ const imageData = tempCtx . createImageData ( width , height )
529+
530+ // Flip vertically while copying pixels
531+ for ( let y = 0 ; y < height ; y ++ ) {
532+ for ( let x = 0 ; x < width ; x ++ ) {
533+ const srcIdx = ( ( height - y - 1 ) * width + x ) * 4
534+ const dstIdx = ( y * width + x ) * 4
535+ imageData . data [ dstIdx ] = pixels [ srcIdx ]
536+ imageData . data [ dstIdx + 1 ] = pixels [ srcIdx + 1 ]
537+ imageData . data [ dstIdx + 2 ] = pixels [ srcIdx + 2 ]
538+ imageData . data [ dstIdx + 3 ] = pixels [ srcIdx + 3 ]
539+ }
540+ }
541+
542+ tempCtx . putImageData ( imageData , 0 , 0 )
543+
544+ // Convert to blob and download
545+ tempCanvas . toBlob ( ( blob ) => {
546+ const url = URL . createObjectURL ( blob )
547+ const a = document . createElement ( "a" )
548+ a . href = url
549+ a . download = `shader_screenshot_${ new Date ( ) . getTime ( ) } .png`
550+ a . click ( )
551+ URL . revokeObjectURL ( url )
552+ statusDiv . textContent = "Screenshot saved!"
553+ setTimeout ( ( ) => ( statusDiv . textContent = "" ) , 3000 )
554+ } , "image/png" )
555+ } , 100 )
517556 } )
518557 </ script >
519558 </ body >
0 commit comments