import { glcompute , canvas } from './gl' ; import { MAX_TOUCH_FORCE_RADIUS_PX , MIN_TOUCH_FORCE_RADIUS_PX , TOUCH_FORCE_RADIUS , TOUCH_FORCE_SCALE , } from './constants' ; import { velocityState , } from './fluid' ; const forceInteractionSource = require ( './kernels/ForceInteractionShader.glsl' ) ; function calcTouchRadius ( width , height ) { return Math . max ( Math . min ( TOUCH_FORCE_RADIUS * Math . max ( width , height ) , MAX_TOUCH_FORCE_RADIUS_PX ) , MIN_TOUCH_FORCE_RADIUS_PX ) ; } const forceInteraction = glcompute . initProgram ( 'forceInteraction' , forceInteractionSource , [ { name : 'u_velocity' , value : 0 , dataType : 'INT' , } , { name : 'u_vector' , value : [ 0 , 0 ] , dataType : 'FLOAT' , } , { name : 'u_scaleFactor' , value : TOUCH_FORCE_SCALE , dataType : 'FLOAT' , } ] ) ; let inputTouches = { } ; canvas . addEventListener ( 'mousemove' , ( e ) => { const x = e . clientX ; const y = e . clientY ; if ( inputTouches . mouse === undefined ) { inputTouches . mouse = { last : [ x , y ] , } ; return ; } const { current } = inputTouches . mouse ; if ( current ) { inputTouches . mouse . last = current ; } inputTouches . mouse . current = [ x , y ] ; } ) ; canvas . addEventListener ( "mouseout" , ( e ) => { if ( e . button === 0 ) { delete inputTouches . mouse ; } } ) ; canvas . addEventListener ( "touchstart" , ( e ) => { for ( let i = 0 ; i < e . changedTouches . length ; i ++ ) { const touch = e . changedTouches [ i ] ; inputTouches [ touch . identifier ] = { last : [ touch . clientX , touch . clientY ] , } ; } } ) ; canvas . addEventListener ( 'touchmove' , ( e ) => { e . preventDefault ( ) ; for ( let i = 0 ; i < e . touches . length ; i ++ ) { const touch = e . touches [ i ] ; const x = touch . clientX ; const y = touch . clientY ; if ( inputTouches [ touch . identifier ] === undefined ) { inputTouches [ touch . identifier ] = { last : [ x , y ] , } ; return ; } const { current } = inputTouches [ touch . identifier ] ; if ( current ) { inputTouches [ touch . identifier ] . last = current ; } inputTouches [ touch . identifier ] . current = [ x , y ] ; } } ) ; canvas . addEventListener ( "touchend" , ( e ) => { for ( let i = 0 ; i < e . changedTouches . length ; i ++ ) { const touch = e . changedTouches [ i ] ; delete inputTouches [ touch . identifier ] ; } } ) ; canvas . addEventListener ( "touchcancel" , ( e ) => { for ( let i = 0 ; i < e . changedTouches . length ; i ++ ) { const touch = e . changedTouches [ i ] ; delete inputTouches [ touch . identifier ] ; } } ) ; document . addEventListener ( 'gesturestart' , disableZoom ) ; document . addEventListener ( 'gesturechange' , disableZoom ) ; document . addEventListener ( 'gestureend' , disableZoom ) ; function disableZoom ( e ) { e . preventDefault ( ) ; const scale = 'scale(1)' ; document . body . style . webkitTransform = scale ; document . body . style . msTransform = scale ; document . body . style . transform = scale ; } export function stepInteraction ( ) { Object . values ( inputTouches ) . forEach ( touch => { const { last , current } = touch ; if ( ! current ) { return ; } if ( current [ 0 ] == last [ 0 ] && current [ 1 ] == last [ 1 ] ) { return ; } const vec = [ current [ 0 ] - last [ 0 ] , - ( current [ 1 ] - last [ 1 ] ) ] as [ number , number ] ; forceInteraction . setUniform ( 'u_vector' , vec , 'FLOAT' ) ; glcompute . stepCircle ( forceInteraction , [ current [ 0 ] , canvas . clientHeight - current [ 1 ] ] , calcTouchRadius ( canvas . clientWidth , canvas . clientHeight ) , [ velocityState ] , velocityState ) ; touch . last = current ; } ) ; }