export class events { getDomElements( ) { const statusElement = document.getElementById( "status" ); const canvas = document.getElementById( "gfx" ); const waveHeightSlider = document.getElementById( "waveHeight" ); const waveHeightValue = document.getElementById( "waveHeightValue" ); const wavelengthSlider = document.getElementById( "wavelengthSlider" ); const wavelengthValue = document.getElementById( "wavelengthValue" ); const resolutionSlider = document.getElementById( "resolutionSlider" ); const resolutionValue = document.getElementById( "resolutionValue" ); const tilingSlider = document.getElementById( "tilingSlider" ); const tilingValue = document.getElementById( "tilingValue" ); const wireframeToggle = document.getElementById( "wireframeToggle" ); const pauseToggle = document.getElementById( "pauseToggle" ); const shadingModeSelect = document.getElementById( "shadingMode" ); const stepButton = document.getElementById( "stepButton" ); const dumpHeightButton = document.getElementById( "dumpHeightButton" ); return { statusElement, canvas, waveHeightSlider, waveHeightValue, wavelengthSlider, wavelengthValue, resolutionSlider, resolutionValue, tilingSlider, tilingValue, wireframeToggle, pauseToggle, shadingModeSelect, stepButton, dumpHeightButton }; } setup( ) { const domElements = this.getDomElements( ); const waveHeightSlider = domElements.waveHeightSlider; const waveHeightValue = domElements.waveHeightValue; const wavelengthSlider = domElements.wavelengthSlider; const wavelengthValue = domElements.wavelengthValue; const resolutionSlider = domElements.resolutionSlider; const resolutionValue = domElements.resolutionValue; const tilingSlider = domElements.tilingSlider; const tilingValue = domElements.tilingValue; const wireframeToggle = domElements.wireframeToggle; const pauseToggle = domElements.pauseToggle; const shadingModeSelect = domElements.shadingModeSelect; const stepButton = domElements.stepButton; const dumpHeightButton = domElements.dumpHeightButton; const getPrimaryPipeline = this.getPrimaryPipeline; const getPipelines = this.getPipelines; const rebuildScene = this.rebuildScene; const getScene = this.getScene; const getRenderSystem = this.getRenderSystem; if ( this.resizeCanvasToDisplay ) { window.addEventListener( "resize", function( ) { this.resizeCanvasToDisplay( ); }.bind( this ) ); } const self = this; if ( waveHeightSlider && waveHeightValue ) { const primary = getPrimaryPipeline( ); waveHeightSlider.value = primary ? String( primary.heightScale ) : "33"; waveHeightValue.textContent = primary ? primary.heightScale.toFixed( 0 ) : "33"; waveHeightSlider.addEventListener( "input", function( event ) { const target = event.target; const value = parseFloat( target.value ); if ( isNaN( value ) ) { return; } const pipelines = getPipelines( ); for ( const p of pipelines ) { p.setHeightScale( value ); } waveHeightValue.textContent = value.toFixed( 0 ); } ); } if ( wavelengthSlider && wavelengthValue ) { const primary = getPrimaryPipeline( ); const initialWavelength = primary && typeof primary.wavelengthScale === "number" ? primary.wavelengthScale : 1.0; wavelengthSlider.value = String( initialWavelength ); wavelengthValue.textContent = initialWavelength.toFixed( 2 ); wavelengthSlider.addEventListener( "input", function( event ) { const target = event.target; const value = parseFloat( target.value ); if ( isNaN( value ) || value <= 0 ) { return; } if ( self.setCurrentWavelengthScale ) { self.setCurrentWavelengthScale( value ); } const pipelines = getPipelines( ); for ( const p of pipelines ) { if ( typeof p.setWavelengthScale === "function" ) { p.setWavelengthScale( value ); } } wavelengthValue.textContent = value.toFixed( 2 ); } ); } if ( wireframeToggle ) { const primary = getPrimaryPipeline( ); wireframeToggle.checked = primary ? primary.renderMode === "wireframe" : false; wireframeToggle.addEventListener( "change", function( event ) { const target = event.target; const pipelines = getPipelines( ); if ( target.checked ) { for ( const p of pipelines ) { p.setRenderMode( "wireframe" ); } } else { for ( const p of pipelines ) { p.setRenderMode( "solid" ); } } rebuildScene( ); } ); } if ( pauseToggle ) { pauseToggle.checked = false; pauseToggle.addEventListener( "change", function( event ) { const target = event.target; const pipelines = getPipelines( ); for ( const p of pipelines ) { p.setPaused( target.checked ); } } ); } if ( shadingModeSelect ) { shadingModeSelect.value = "lighting"; shadingModeSelect.addEventListener( "change", function( event ) { const target = event.target; const value = target.value; const pipelines = getPipelines( ); for ( const p of pipelines ) { p.setShadingMode( value ); } } ); } if ( stepButton ) { stepButton.addEventListener( "click", function( ) { const pipelines = getPipelines( ); for ( const p of pipelines ) { p.stepOnce( 1 / 60 ); } const scene = getScene( ); const renderSystem = getRenderSystem( ); if ( scene && renderSystem ) { renderSystem.render( scene ); } } ); } if ( dumpHeightButton ) { dumpHeightButton.addEventListener( "click", function( ) { const pipeline = getPrimaryPipeline( ); if ( !pipeline ) { return; } const block = pipeline.getBlockByName( "ocean" ); if ( !block ) { return; } const colPass = block.getPass( "ColFFT" ); if ( !colPass || !colPass.shader ) { return; } colPass.shader.debugBuffer( "heightField" ) .then( function( data ) { if ( !data || !data.length ) { console.log( "heightField debug: empty buffer" ); return; } let min = data[ 0 ]; let max = data[ 0 ]; let sum = 0; for ( let i = 0; i < data.length; i++ ) { const v = data[ i ]; if ( v < min ) min = v; if ( v > max ) max = v; sum += v; } const avg = sum / data.length; console.log( "heightField debug:", "size =", data.length, "min =", min, "max =", max, "avg =", avg ); } ) .catch( function( error ) { console.error( "heightField debug failed:", error ); } ); } ); } if ( resolutionSlider && resolutionValue ) { const applyResolutionFromSlider = function( ) { const raw = parseFloat( resolutionSlider.value ); if ( isNaN( raw ) ) { return; } let targetSize = 64; if ( raw < 48 ) { targetSize = 32; } else if ( raw < 96 ) { targetSize = 64; } else if ( raw < 192 ) { targetSize = 128; } else if ( raw < 384 ) { targetSize = 256; } else if ( raw < 768 ) { targetSize = 512; } else if ( raw < 1536 ) { targetSize = 1024; } else { targetSize = 2048; } resolutionSlider.value = String( targetSize ); resolutionValue.textContent = String( targetSize ); if ( self.setCurrentMeshResolution ) { self.setCurrentMeshResolution( targetSize ); } rebuildScene( ); }; applyResolutionFromSlider( ); resolutionSlider.addEventListener( "input", function( ) { applyResolutionFromSlider( ); } ); } if ( tilingSlider && tilingValue ) { const applyTilingFromSlider = function( ) { const raw = parseInt( tilingSlider.value, 10 ); if ( isNaN( raw ) || raw < 1 ) { return; } const tileRange = raw - 1; tilingValue.textContent = String( raw ); if ( self.setCurrentTiling ) { self.setCurrentTiling( raw ); } rebuildScene( ); }; applyTilingFromSlider( ); tilingSlider.addEventListener( "input", function( ) { applyTilingFromSlider( ); } ); } if ( domElements.canvas && this.setAutoRotate ) { domElements.canvas.addEventListener( "pointerdown", function( ) { this.setAutoRotate( false ); }.bind( this ) ); } } }