@@ -27,10 +27,6 @@ const OUT_POSITION = "oP";
2727const OUT_LIFE = "oL" ;
2828const OUT_VELOCITY = "oV" ;
2929
30- /** module scoped global variables/constants */
31- let mouseX = 0 ,
32- mouseY = 0 ;
33-
3430type Vector2D = [ number , number ] ;
3531
3632export interface ParticlesOptions {
@@ -50,6 +46,10 @@ export interface ParticlesOptions {
5046 ageRange ?: [ number , number ] ;
5147 /** [minSpeed, maxSpeed] */
5248 speedRange ?: [ number , number ] ;
49+ /** Initial origin -> Will update as per mouse position when mouse moved if mouseOff is not set.
50+ * @defaultValue [0, 0]
51+ */
52+ origin ?: [ number , number ] ;
5353 /** todo */
5454 /** todo: WIP constant force [fx, fy] or a force field texture */
5555 forceField ?: Vector2D ; //| Vector[][] | string;
@@ -65,12 +65,14 @@ const defaultOptions: ParticlesOptions = {
6565 ageRange : [ 2 , 10 ] ,
6666} ;
6767
68+ /** generate initial data for the simulation */
6869const getInitialData = ( maxParticles : number ) => {
6970 const data = [ ] ;
70- for ( let i = 0 ; i < maxParticles ; i ++ ) data . push ( 0 , 0 , 1 , 0 , 0 ) ;
71+ for ( let i = 0 ; i < maxParticles ; i ++ ) data . push ( 0 , 0 , 0. 1, 0 , 0 ) ;
7172 return data ;
7273} ;
7374
75+ /** generate random RG data for source of randomness within the simulation */
7476const randomRGData = ( sizeX : number , sizeY : number ) : Uint8Array => {
7577 const data = [ ] ;
7678 for ( let i = 0 ; i < sizeX * sizeY ; i ++ ) data . push ( random ( ) * 255.0 , random ( ) * 255.0 ) ;
@@ -79,14 +81,15 @@ const randomRGData = (sizeX: number, sizeY: number): Uint8Array => {
7981
8082/** Particles simulator */
8183const simulate = (
82- canvas : HTMLCanvasElement ,
84+ _canvas : HTMLCanvasElement ,
8385 gl : WebGL2RenderingContext ,
8486 options : ParticlesOptions ,
8587) => {
86- /** Normalize options */
87- options . angleRage ?. map ( a => a % PI ) . sort ( ) ;
88- options . ageRange ?. sort ( ) ;
89- options . speedRange ?. sort ( ) ;
88+ /** todo Normalize options
89+ * canvas positions are between -1 to 1 on all axes
90+ */
91+ // skipcq: JS-0339 -- defined in default options
92+ const angleRage = options . angleRage ! as [ number , number ] ;
9093 /** Create shader */
9194 const createShader = ( type : number , source : string ) : WebGLShader => {
9295 const shader = gl . createShader ( type ) ;
@@ -105,6 +108,7 @@ const simulate = (
105108 return shader ;
106109 } ;
107110
111+ /** Create program */
108112 const createProgram = (
109113 vertexShaderSource : string ,
110114 fragmentShaderSource : string ,
@@ -227,11 +231,17 @@ const simulate = (
227231 const location = gl . getUniformLocation ( updateProgram , name ) ;
228232 y ? gl . uniform2f ( location , x , y ) : gl . uniform1f ( location , x ) ;
229233 } ;
230- let bornParticles = 0 ;
231234 let prevT = 0 ;
235+ let bornParticles = 0 ;
232236 let readIndex = 0 ;
233237 let writeIndex = 1 ;
238+ let mouseX = 0 ;
239+ let mouseY = 0 ;
234240
241+ const setOrigin = ( x : number , y : number ) : void => {
242+ mouseX = x ;
243+ mouseY = y ;
244+ } ;
235245 /** The render loop */
236246 const render = ( timeStamp : number ) : void => {
237247 let dt = timeStamp - prevT ;
@@ -246,13 +256,12 @@ const simulate = (
246256 // skipcq: JS-0339 -- forcefield is always set by the default options
247257 setUpdateUniform ( U_FORCE_FIELD , ...options . forceField ! ) ;
248258 setUpdateUniform ( U_ORIGIN , mouseX , mouseY ) ;
249- // skipcq: JS-0339 -- set in default options
250- setUpdateUniform ( U_ANGLE_RANGE , ...options . angleRage ! ) ;
259+ setUpdateUniform ( U_ANGLE_RANGE , ...angleRage ) ;
251260 // skipcq: JS-0339 -- set in default options
252261 setUpdateUniform ( U_LIFE_RANGE , ...options . ageRange ! ) ;
253262 // skipcq: JS-0339 -- set in default options
254263 const speedRange = options . speedRange ! ;
255- setUpdateUniform ( U_SPEED_RANGE , speedRange [ 0 ] / canvas . width , speedRange [ 1 ] / canvas . height ) ;
264+ setUpdateUniform ( U_SPEED_RANGE , speedRange [ 0 ] , speedRange [ 1 ] ) ;
256265 gl . activeTexture ( gl . TEXTURE0 ) ;
257266 gl . bindTexture ( gl . TEXTURE_2D , rgNoiseTexture ) ;
258267 setUpdateUniform ( U_RANDOM_RG , 0 ) ;
@@ -277,7 +286,7 @@ const simulate = (
277286 // skipcq: JS-0339
278287 options . maxParticles ! ,
279288 // skipcq: JS-0339
280- Math . floor ( bornParticles + options . maxParticles ! * options . generationRate ! ) ,
289+ Math . floor ( bornParticles + dt * options . generationRate ! ) ,
281290 ) ;
282291
283292 requestAnimationFrame ( ts => {
@@ -288,6 +297,7 @@ const simulate = (
288297 requestAnimationFrame ( ts => {
289298 render ( ts ) ;
290299 } ) ;
300+ return setOrigin ;
291301} ;
292302
293303/**
@@ -301,22 +311,22 @@ export const renderParticles = (canvas: HTMLCanvasElement, options?: ParticlesOp
301311 const gl = canvas . getContext ( "webgl2" ) ;
302312 if ( ! gl ) return undefined ;
303313
304- simulate ( canvas , gl , { ...defaultOptions , ...options } ) ;
314+ const setOrigin = simulate ( canvas , gl , { ...defaultOptions , ...options } ) ;
315+ options ?. origin && setOrigin ( ...options . origin ) ;
305316
306317 /** Set up observer to observe size changes */
307318 const observer = new ResizeObserver ( entries => {
308319 const { width, height } = entries [ 0 ] . contentRect ;
309320 canvas . width = width ;
310321 canvas . height = height ;
311- gl . viewport ( 0 , 0 , gl . drawingBufferWidth , gl . drawingBufferHeight ) ;
322+ gl . viewport ( 0 , 0 , canvas . width , canvas . height ) ;
312323 } ) ;
313324 observer . observe ( canvas ) ;
314325
315326 const target = options ?. overlay ? window : canvas ;
316327 /** update mouse position */
317328 const onMouseMove = ( e : MouseEvent ) => {
318- mouseX = ( e . clientX / canvas . width ) * 2 - 1 ;
319- mouseY = 1 - ( e . clientY / canvas . height ) * 2 ;
329+ setOrigin ( ( e . clientX / canvas . width ) * 2 - 1 , 1 - ( e . clientY / canvas . height ) * 2 ) ;
320330 } ;
321331
322332 // @ts -expect-error -- strange type-error
@@ -328,13 +338,3 @@ export const renderParticles = (canvas: HTMLCanvasElement, options?: ParticlesOp
328338 ! options ?. mouseOff && target . removeEventListener ( "mousemove" , onMouseMove ) ;
329339 } ;
330340} ;
331-
332- /**
333- * Should allow users to set origin manually?
334- */
335-
336- /** Extra functions */
337- export const setOrigin = ( x : number , y : number ) => {
338- mouseX = x ;
339- mouseY = y ;
340- } ;
0 commit comments