class RotoZoom implements Effect { private width : number ; private height : number ; private src : ImageData ; private angle : number = 0 ; public async init ( width , height ) { this . width = width ; this . height = height ; this . src = await demoFX . loadImage ( "2ndreal.jpg" ) ; } public render ( ctx , _ ) { const dest = ctx . getImageData ( 0 , 0 , this . width , this . height ) ; const c = Math . cos ( this . angle * Math . PI / 180 ) ; const s = Math . sin ( this . angle * Math . PI / 180 ) ; this . angle ++ ; this . angle %= 360 ; let destOfs = 0 ; for ( let y = 0 ; y < this . height ; y ++ ) { for ( let x = 0 ; x < this . width ; x ++ ) { const u = Math . floor ( ( x * c - y * s ) * ( s + 1 ) ) & 0xff ; let v = Math . floor ( ( x * s + y * c ) * ( s + 1 ) ) % this . src . height ; while ( v < 0 ) { v += this . src . height ; } let srcOfs = ( u + ( v << 8 ) ) << 2 ; dest . data [ destOfs ++ ] = this . src . data [ srcOfs ++ ] ; dest . data [ destOfs ++ ] = this . src . data [ srcOfs ++ ] ; dest . data [ destOfs ++ ] = this . src . data [ srcOfs ++ ] ; dest . data [ destOfs ++ ] = this . src . data [ srcOfs ++ ] ; } } ctx . putImageData ( dest , 0 , 0 ) ; } } demoFX . register ( "rotozoom" , new RotoZoom ( ) ) ;