@ -96,6 +96,119 @@ function draw_html(state) { 
			
		
	
		
		
			
				
					
					} }  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					function  draw _strokes ( state ,  width ,  height ,  programs ,  gl ,  lod _levels ,  segment _count ,   
			
		
	
		
		
			
				
					
					    total _lod _floats ,  total _lod _indices ,  
			
		
	
		
		
			
				
					
					    batches _tv ,  
			
		
	
		
		
			
				
					
					    points _tv ,  
			
		
	
		
		
			
				
					
					    ids _tv ,  
			
		
	
		
		
			
				
					
					    pressures _tv ,  
			
		
	
		
		
			
				
					
					    vbo ,  
			
		
	
		
		
			
				
					
					    ebo ,  
			
		
	
		
		
			
				
					
					    stroke _texture ,  
			
		
	
		
		
			
				
					
					    stroke _data ,  
			
		
	
		
		
			
				
					
					    stroke _count ,  
			
		
	
		
		
			
				
					
					)  {  
			
		
	
		
		
			
				
					
					    const  pr  =  programs [ 'main' ] ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    // Last pair (lod unused) to have a proper from;to
  
			
		
	
		
		
			
				
					
					    tv _add2 ( batches _tv ,  segment _count ) ;  
			
		
	
		
		
			
				
					
					    tv _add2 ( batches _tv ,  - 1 ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    gl . clear ( gl . DEPTH _BUFFER _BIT ) ;  // draw strokes above the images 
  
			
		
	
		
		
			
				
					
					    gl . useProgram ( pr . program ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    const  total _size  =  points _tv . size  *  4  +  
			
		
	
		
		
			
				
					
					        ids _tv . size  *  4  +  
			
		
	
		
		
			
				
					
					        round _to _pow2 ( pressures _tv . size ,  4 )  +  
			
		
	
		
		
			
				
					
					        total _lod _floats  *  4 ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    gl . bindBuffer ( gl . ARRAY _BUFFER ,  vbo ) ;  
			
		
	
		
		
			
				
					
					    gl . bufferData ( gl . ARRAY _BUFFER ,  total _size ,  gl . STREAM _DRAW ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    // Segment points, segment stroke ids, segment pressures
  
			
		
	
		
		
			
				
					
					    gl . bufferSubData ( gl . ARRAY _BUFFER ,  0 ,  tv _data ( points _tv ) ) ;   
			
		
	
		
		
			
				
					
					    gl . bufferSubData ( gl . ARRAY _BUFFER ,  points _tv . size  *  4 ,  tv _data ( ids _tv ) ) ;  
			
		
	
		
		
			
				
					
					    gl . bufferSubData ( gl . ARRAY _BUFFER ,  points _tv . size  *  4  +  ids _tv . size  *  4 ,  tv _data ( pressures _tv ) ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    gl . bindBuffer ( gl . ELEMENT _ARRAY _BUFFER ,  ebo ) ;  
			
		
	
		
		
			
				
					
					    gl . bufferData ( gl . ELEMENT _ARRAY _BUFFER ,  total _lod _indices  *  4 ,  gl . STREAM _DRAW ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    // Upload all variants of LOD vertices/indices
  
			
		
	
		
		
			
				
					
					    const  base _lod _points _offset  =  points _tv . size  *  4  +  ids _tv . size  *  4  +  round _to _pow2 ( pressures _tv . size ,  4 ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    for  ( const  level  of  lod _levels )  {  
			
		
	
		
		
			
				
					
					        gl . bufferSubData ( gl . ARRAY _BUFFER ,  base _lod _points _offset  +  level . vertices _offset ,  tv _data ( level . data . points ) ) ;  
			
		
	
		
		
			
				
					
					        gl . bufferSubData ( gl . ELEMENT _ARRAY _BUFFER ,  level . indices _offset ,  tv _data ( level . data . indices ) ) ;  
			
		
	
		
		
			
				
					
					    }  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    // Per-stroke data (base width, color)
  
			
		
	
		
		
			
				
					
					    gl . bindTexture ( gl . TEXTURE _2D ,  stroke _texture ) ;  
			
		
	
		
		
			
				
					
					    upload _square _rgba16ui _texture ( gl ,  stroke _data ,  config . stroke _texture _size ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    gl . uniform2f ( pr . locations [ 'u_res' ] ,  width ,  height ) ;  
			
		
	
		
		
			
				
					
					    gl . uniform2f ( pr . locations [ 'u_scale' ] ,  state . canvas . zoom ,  state . canvas . zoom ) ;  
			
		
	
		
		
			
				
					
					    gl . uniform2f ( pr . locations [ 'u_translation' ] ,  state . canvas . offset . x ,  state . canvas . offset . y ) ;  
			
		
	
		
		
			
				
					
					    gl . uniform1i ( pr . locations [ 'u_stroke_count' ] ,  stroke _count ) ;  
			
		
	
		
		
			
				
					
					    gl . uniform1i ( pr . locations [ 'u_debug_mode' ] ,  state . debug . red ) ;  
			
		
	
		
		
			
				
					
					    gl . uniform1i ( pr . locations [ 'u_stroke_data' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					    gl . uniform1i ( pr . locations [ 'u_stroke_texture_size' ] ,  config . stroke _texture _size ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    gl . enableVertexAttribArray ( pr . locations [ 'a_pos' ] ) ;  
			
		
	
		
		
			
				
					
					    gl . enableVertexAttribArray ( pr . locations [ 'a_a' ] ) ;  
			
		
	
		
		
			
				
					
					    gl . enableVertexAttribArray ( pr . locations [ 'a_b' ] ) ;  
			
		
	
		
		
			
				
					
					    gl . enableVertexAttribArray ( pr . locations [ 'a_stroke_id' ] ) ;  
			
		
	
		
		
			
				
					
					    gl . enableVertexAttribArray ( pr . locations [ 'a_pressure' ] ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    gl . vertexAttribDivisor ( pr . locations [ 'a_pos' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					    gl . vertexAttribDivisor ( pr . locations [ 'a_a' ] ,  1 ) ;  
			
		
	
		
		
			
				
					
					    gl . vertexAttribDivisor ( pr . locations [ 'a_b' ] ,  1 ) ;  
			
		
	
		
		
			
				
					
					    gl . vertexAttribDivisor ( pr . locations [ 'a_stroke_id' ] ,  1 ) ;  
			
		
	
		
		
			
				
					
					    gl . vertexAttribDivisor ( pr . locations [ 'a_pressure' ] ,  1 ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    for  ( let  b  =  0 ;  b  <  batches _tv . size  -  2 ;  b  +=  2 )  {  
			
		
	
		
		
			
				
					
					        const  batch _from  =  batches _tv . data [ b  +  0 ] ;  
			
		
	
		
		
			
				
					
					        const  batch _size  =  batches _tv . data [ b  +  2 ]  -  batch _from ;  
			
		
	
		
		
			
				
					
					        let  lod _level  =  batches _tv . data [ b  +  1 ] ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        if  ( config . debug _force _lod  !==  null )  {  
			
		
	
		
		
			
				
					
					            lod _level  =  config . debug _force _lod ;    
			
		
	
		
		
			
				
					
					        }  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        const  level  =  lod _levels [ lod _level ] ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        if  ( batch _size  >  0 )  {  
			
		
	
		
		
			
				
					
					            //stat_total_vertices += batch_size * level.data.indices.size;
  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					            gl . uniform1i ( pr . locations [ 'u_circle_points' ] ,  level . data . points . size  /  2  -  4 ) ;  
			
		
	
		
		
			
				
					
					            gl . uniform3f ( pr . locations [ 'u_debug_color' ] ,   
			
		
	
		
		
			
				
					
					                ( lod _level  *  785892  +  125127 )  %  8  /  7 ,  
			
		
	
		
		
			
				
					
					                ( lod _level  *  901824  +  985835 )  %  8  /  7 ,  
			
		
	
		
		
			
				
					
					                ( lod _level  *  232181  +  838533 )  %  8  /  7 ,  
			
		
	
		
		
			
				
					
					            ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					            // Points (a, b) and stroke ids are stored in separate cpu buffers so that points can be reused (look at stride and offset values)
  
			
		
	
		
		
			
				
					
					            gl . vertexAttribPointer ( pr . locations [ 'a_a' ] ,  2 ,  gl . FLOAT ,  false ,  2  *  4 ,  batch _from  *  2  *  4 ) ;  
			
		
	
		
		
			
				
					
					            gl . vertexAttribPointer ( pr . locations [ 'a_b' ] ,  2 ,  gl . FLOAT ,  false ,  2  *  4 ,  batch _from  *  2  *  4  +  2  *  4 ) ;  
			
		
	
		
		
			
				
					
					            gl . vertexAttribIPointer ( pr . locations [ 'a_stroke_id' ] ,  1 ,  gl . INT ,  4 ,  points _tv . size  *  4  +  batch _from  *  4 ) ;  
			
		
	
		
		
			
				
					
					            gl . vertexAttribPointer ( pr . locations [ 'a_pressure' ] ,  2 ,  gl . UNSIGNED _BYTE ,  true ,  1 ,  points _tv . size  *  4  +  ids _tv . size  *  4  +  batch _from ) ;  
			
		
	
		
		
			
				
					
					            gl . vertexAttribPointer ( pr . locations [ 'a_pos' ] ,  2 ,  gl . FLOAT ,  false ,  2  *  4 ,  base _lod _points _offset  +  level . vertices _offset ,  4 ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					            gl . drawElementsInstanced ( gl . TRIANGLES ,  level . data . indices . size ,  gl . UNSIGNED _INT ,  level . indices _offset ,  batch _size ) ;   
			
		
	
		
		
			
				
					
					        }  
			
		
	
		
		
			
				
					
					    }  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    // I don't really know why I need to do this, but it
  
			
		
	
		
		
			
				
					
					    // makes background patter drawcall work properly
  
			
		
	
		
		
			
				
					
					    gl . vertexAttribDivisor ( pr . locations [ 'a_pos' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					    gl . vertexAttribDivisor ( pr . locations [ 'a_a' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					    gl . vertexAttribDivisor ( pr . locations [ 'a_b' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					    gl . vertexAttribDivisor ( pr . locations [ 'a_stroke_id' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					    gl . vertexAttribDivisor ( pr . locations [ 'a_pressure' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    tv _pop ( batches _tv ) ;  
			
		
	
		
		
			
				
					
					    tv _pop ( batches _tv ) ;  
			
		
	
		
		
			
				
					
					}  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					async  function  draw ( state ,  context ,  animate ,  ts )  { async  function  draw ( state ,  context ,  animate ,  ts )  {  
			
		
	
		
		
			
				
					
					    const  dt  =  ts  -  context . last _frame _ts ;     const  dt  =  ts  -  context . last _frame _ts ;  
			
		
	
		
		
			
				
					
					    const  cpu _before  =  performance . now ( ) ;     const  cpu _before  =  performance . now ( ) ;  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -291,173 +404,40 @@ async function draw(state, context, animate, ts) { 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    // "Static" data upload
     // "Static" data upload
  
			
		
	
		
		
			
				
					
					    if  ( segment _count  >  0 )  {     if  ( segment _count  >  0 )  {  
			
		
	
		
		
			
				
					
					        const  pr  =  programs [ 'main' ] ;         draw _strokes ( state ,  context . canvas . width ,  context . canvas . height ,  programs ,  gl ,  lod _levels ,  segment _count ,   
			
				
				
			
		
	
		
		
			
				
					
					
            total _lod _floats ,  
			
				
				
			
		
	
		
		
			
				
					
					        // Last pair (lod unused) to have a proper from;to
             total _lod _indices ,  
			
				
				
			
		
	
		
		
			
				
					
					        tv _add2 ( context . instance _data _batches ,  segment _count ) ;             context . instance _data _batches ,  
			
				
				
			
		
	
		
		
			
				
					
					        tv _add2 ( context . instance _data _batches ,  - 1 ) ;             context . instance _data _points ,  
			
				
				
			
		
	
		
		
			
				
					
					
            context . instance _data _ids ,  
			
				
				
			
		
	
		
		
			
				
					
					        gl . clear ( gl . DEPTH _BUFFER _BIT ) ;  // draw strokes above the images 
             context . instance _data _pressures ,  
			
				
				
			
		
	
		
		
			
				
					
					        gl . useProgram ( pr . program ) ;             buffers [ 'b_strokes_static' ] ,  
			
				
				
			
		
	
		
		
			
				
					
					
            buffers [ 'i_strokes_static' ] ,  
			
				
				
			
		
	
		
		
			
				
					
					        const  total _static _size  =  context . instance _data _points . size  *  4  +             textures [ 'stroke_data' ] ,  
			
				
				
			
		
	
		
		
			
				
					
					            context . instance _data _ids . size  *  4  +             context . stroke _data ,  
			
				
				
			
		
	
		
		
			
				
					
					            round _to _pow2 ( context . instance _data _pressures . size ,  4 )  +             state . events . length ,  // not really 
  
			
				
				
			
		
	
		
		
			
				
					
					            total _lod _floats  *  4 ;         ) ;  
			
				
				
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . bindBuffer ( gl . ARRAY _BUFFER ,  buffers [ 'b_strokes_static' ] ) ;  
			
		
	
		
		
			
				
					
					        gl . bufferData ( gl . ARRAY _BUFFER ,  total _static _size ,  gl . STREAM _DRAW ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        // Segment points, segment stroke ids, segment pressures
  
			
		
	
		
		
			
				
					
					        gl . bufferSubData ( gl . ARRAY _BUFFER ,  0 ,  tv _data ( context . instance _data _points ) ) ;   
			
		
	
		
		
			
				
					
					        gl . bufferSubData ( gl . ARRAY _BUFFER ,  context . instance _data _points . size  *  4 ,  tv _data ( context . instance _data _ids ) ) ;  
			
		
	
		
		
			
				
					
					        gl . bufferSubData ( gl . ARRAY _BUFFER ,  context . instance _data _points . size  *  4  +  context . instance _data _ids . size  *  4 ,  
			
		
	
		
		
			
				
					
					            tv _data ( context . instance _data _pressures ) ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . bindBuffer ( gl . ELEMENT _ARRAY _BUFFER ,  buffers [ 'i_strokes_static' ] ) ;  
			
		
	
		
		
			
				
					
					        gl . bufferData ( gl . ELEMENT _ARRAY _BUFFER ,  total _lod _indices  *  4 ,  gl . STREAM _DRAW ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        // Upload all variants of LOD vertices/indices
  
			
		
	
		
		
			
				
					
					        const  base _lod _points _offset  =  context . instance _data _points . size  *  4  +  context . instance _data _ids . size  *  4  +  round _to _pow2 ( context . instance _data _pressures . size ,  4 ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        for  ( const  level  of  lod _levels )  {  
			
		
	
		
		
			
				
					
					            gl . bufferSubData ( gl . ARRAY _BUFFER ,  base _lod _points _offset  +  level . vertices _offset ,  tv _data ( level . data . points ) ) ;  
			
		
	
		
		
			
				
					
					            gl . bufferSubData ( gl . ELEMENT _ARRAY _BUFFER ,  level . indices _offset ,  tv _data ( level . data . indices ) ) ;  
			
		
	
		
		
			
				
					
					        }  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        // Per-stroke data (base width, color)
  
			
		
	
		
		
			
				
					
					        gl . bindTexture ( gl . TEXTURE _2D ,  textures [ 'stroke_data' ] ) ;  
			
		
	
		
		
			
				
					
					        upload _square _rgba16ui _texture ( gl ,  context . stroke _data ,  config . stroke _texture _size ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . uniform2f ( pr . locations [ 'u_res' ] ,  context . canvas . width ,  context . canvas . height ) ;  
			
		
	
		
		
			
				
					
					        gl . uniform2f ( pr . locations [ 'u_scale' ] ,  state . canvas . zoom ,  state . canvas . zoom ) ;  
			
		
	
		
		
			
				
					
					        gl . uniform2f ( pr . locations [ 'u_translation' ] ,  state . canvas . offset . x ,  state . canvas . offset . y ) ;  
			
		
	
		
		
			
				
					
					        gl . uniform1i ( pr . locations [ 'u_stroke_count' ] ,  state . events . length ) ;  
			
		
	
		
		
			
				
					
					        gl . uniform1i ( pr . locations [ 'u_debug_mode' ] ,  state . debug . red ) ;  
			
		
	
		
		
			
				
					
					        gl . uniform1i ( pr . locations [ 'u_stroke_data' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					        gl . uniform1i ( pr . locations [ 'u_stroke_texture_size' ] ,  config . stroke _texture _size ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . enableVertexAttribArray ( pr . locations [ 'a_pos' ] ) ;  
			
		
	
		
		
			
				
					
					        gl . enableVertexAttribArray ( pr . locations [ 'a_a' ] ) ;  
			
		
	
		
		
			
				
					
					        gl . enableVertexAttribArray ( pr . locations [ 'a_b' ] ) ;  
			
		
	
		
		
			
				
					
					        gl . enableVertexAttribArray ( pr . locations [ 'a_stroke_id' ] ) ;  
			
		
	
		
		
			
				
					
					        gl . enableVertexAttribArray ( pr . locations [ 'a_pressure' ] ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_pos' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_a' ] ,  1 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_b' ] ,  1 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_stroke_id' ] ,  1 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_pressure' ] ,  1 ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        for  ( let  b  =  0 ;  b  <  context . instance _data _batches . size  -  2 ;  b  +=  2 )  {  
			
		
	
		
		
			
				
					
					            const  batch _from  =  context . instance _data _batches . data [ b  +  0 ] ;  
			
		
	
		
		
			
				
					
					            const  batch _size  =  context . instance _data _batches . data [ b  +  2 ]  -  batch _from ;  
			
		
	
		
		
			
				
					
					            let  lod _level  =  context . instance _data _batches . data [ b  +  1 ] ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					            if  ( config . debug _force _lod  !==  null )  {  
			
		
	
		
		
			
				
					
					                lod _level  =  config . debug _force _lod ;    
			
		
	
		
		
			
				
					
					            }  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					            const  level  =  lod _levels [ lod _level ] ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					            if  ( batch _size  >  0 )  {  
			
		
	
		
		
			
				
					
					                stat _total _vertices  +=  batch _size  *  level . data . indices . size ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					                gl . uniform1i ( pr . locations [ 'u_circle_points' ] ,  level . data . points . size  /  2  -  4 ) ;  
			
		
	
		
		
			
				
					
					                gl . uniform3f ( pr . locations [ 'u_debug_color' ] ,   
			
		
	
		
		
			
				
					
					                    ( lod _level  *  785892  +  125127 )  %  8  /  7 ,  
			
		
	
		
		
			
				
					
					                    ( lod _level  *  901824  +  985835 )  %  8  /  7 ,  
			
		
	
		
		
			
				
					
					                    ( lod _level  *  232181  +  838533 )  %  8  /  7 ,  
			
		
	
		
		
			
				
					
					                ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					                // Points (a, b) and stroke ids are stored in separate cpu buffers so that points can be reused (look at stride and offset values)
  
			
		
	
		
		
			
				
					
					                gl . vertexAttribPointer ( pr . locations [ 'a_a' ] ,  2 ,  gl . FLOAT ,  false ,  2  *  4 ,  batch _from  *  2  *  4 ) ;  
			
		
	
		
		
			
				
					
					                gl . vertexAttribPointer ( pr . locations [ 'a_b' ] ,  2 ,  gl . FLOAT ,  false ,  2  *  4 ,  batch _from  *  2  *  4  +  2  *  4 ) ;  
			
		
	
		
		
			
				
					
					                gl . vertexAttribIPointer ( pr . locations [ 'a_stroke_id' ] ,  1 ,  gl . INT ,  4 ,  context . instance _data _points . size  *  4  +  batch _from  *  4 ) ;  
			
		
	
		
		
			
				
					
					                gl . vertexAttribPointer ( pr . locations [ 'a_pressure' ] ,  2 ,  gl . UNSIGNED _BYTE ,  true ,  1 ,  context . instance _data _points . size  *  4  +  context . instance _data _ids . size  *  4  +  batch _from ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					                gl . vertexAttribPointer ( pr . locations [ 'a_pos' ] ,  2 ,  gl . FLOAT ,  false ,  2  *  4 ,  base _lod _points _offset  +  level . vertices _offset ,  4 ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					                gl . drawElementsInstanced ( gl . TRIANGLES ,  level . data . indices . size ,  gl . UNSIGNED _INT ,  level . indices _offset ,  batch _size ) ;   
			
		
	
		
		
			
				
					
					            }  
			
		
	
		
		
			
				
					
					        }  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        // I don't really know why I need to do this, but it
  
			
		
	
		
		
			
				
					
					        // makes background patter drawcall work properly
  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_pos' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_a' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_b' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_stroke_id' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_pressure' ] ,  0 ) ;  
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					    }     }  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    // Dynamic draw (strokes currently being drawn)
     // Dynamic draw (strokes currently being drawn)
  
			
		
	
		
		
			
				
					
					    if  ( false  &&  dynamic _segment _count  >  0 )  {     if  ( dynamic _segment _count  >  0 )  {  
			
				
				
			
		
	
		
		
			
				
					
					        const  pr  =  programs [ 'main' ] ;  // same as static
  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
	
		
		
			
				
					
					        // Dynamic strokes should be drawn above static strokes
         // Dynamic strokes should be drawn above static strokes
  
			
		
	
		
		
			
				
					
					        gl . clear ( gl . DEPTH _BUFFER _BIT ) ;         gl . clear ( gl . DEPTH _BUFFER _BIT ) ;  
			
		
	
		
		
			
				
					
					        gl . useProgram ( pr . program ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . uniform1i ( pr . locations [ 'u_stroke_count' ] ,  dynamic _stroke _count ) ;  
			
		
	
		
		
			
				
					
					        gl . uniform1i ( pr . locations [ 'u_stroke_data' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					        gl . uniform1i ( pr . locations [ 'u_stroke_texture_size' ] ,  config . dynamic _stroke _texture _size ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . bindBuffer ( gl . ARRAY _BUFFER ,  buffers [ 'b_strokes_dynamic' ] ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        // Dynamic data upload
  
			
		
	
		
		
			
				
					
					        const  total _dynamic _size  =   
			
		
	
		
		
			
				
					
					            context . dynamic _instance _points . size  *  4  +  context . dynamic _instance _ids . size  *  4  +   
			
		
	
		
		
			
				
					
					            context . dynamic _instance _pressure . size ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . bufferData ( gl . ARRAY _BUFFER ,  total _dynamic _size ,  gl . STREAM _DRAW ) ;  
			
		
	
		
		
			
				
					
					        gl . bufferSubData ( gl . ARRAY _BUFFER ,  0 ,  tv _data ( context . dynamic _instance _points ) ) ;   
			
		
	
		
		
			
				
					
					        gl . bufferSubData ( gl . ARRAY _BUFFER ,  context . dynamic _instance _points . size  *  4 ,  tv _data ( context . dynamic _instance _ids ) ) ;  
			
		
	
		
		
			
				
					
					        gl . bufferSubData ( gl . ARRAY _BUFFER ,  context . dynamic _instance _points . size  *  4  +  context . dynamic _instance _ids . size  *  4 ,   
			
		
	
		
		
			
				
					
					            tv _data ( context . dynamic _instance _pressure ) ) ;  
			
		
	
		
		
			
				
					
					        gl . bindTexture ( gl . TEXTURE _2D ,  textures [ 'dynamic_stroke_data' ] ) ;  
			
		
	
		
		
			
				
					
					        upload _square _rgba16ui _texture ( gl ,  context . dynamic _stroke _data ,  config . dynamic _stroke _texture _size ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . uniform2f ( pr . locations [ 'u_res' ] ,  context . canvas . width ,  context . canvas . height ) ;         draw _strokes ( state ,  context . canvas . width ,  context . canvas . height ,  programs ,  gl ,  lod _levels ,  dynamic _segment _count ,   
			
				
				
			
		
	
		
		
			
				
					
					        gl . uniform2f ( pr . locations [ 'u_scale' ] ,  state . canvas . zoom ,  state . canvas . zoom ) ;             total _lod _floats ,  
			
				
				
			
		
	
		
		
			
				
					
					        gl . uniform2f ( pr . locations [ 'u_translation' ] ,  state . canvas . offset . x ,  state . canvas . offset . y ) ;             total _lod _indices ,  
			
				
				
			
		
	
		
		
			
				
					
					                        context . dynamic _instance _batches ,  
			
				
				
			
		
	
		
		
			
				
					
					        gl . uniform1i ( pr . locations [ 'u_stroke_count' ] ,  context . dynamic _stroke _count ) ;             context . dynamic _instance _points ,  
			
				
				
			
		
	
		
		
			
				
					
					        gl . uniform1i ( pr . locations [ 'u_debug_mode' ] ,  state . debug . red ) ;             context . dynamic _instance _ids ,  
			
				
				
			
		
	
		
		
			
				
					
					        gl . uniform1i ( pr . locations [ 'u_stroke_data' ] ,  0 ) ;             context . dynamic _instance _pressure ,  
			
				
				
			
		
	
		
		
			
				
					
					        gl . uniform1i ( pr . locations [ 'u_stroke_texture_size' ] ,  config . dynamic _stroke _texture _size ) ;             buffers [ 'b_strokes_dynamic' ] ,  
			
				
				
			
		
	
		
		
			
				
					
					
            buffers [ 'i_strokes_dynamic' ] ,  
			
				
				
			
		
	
		
		
			
				
					
					        gl . enableVertexAttribArray ( pr . locations [ 'a_a' ] ) ;             textures [ 'dynamic_stroke_data' ] ,  
			
				
				
			
		
	
		
		
			
				
					
					        gl . enableVertexAttribArray ( pr . locations [ 'a_b' ] ) ;             context . dynamic _stroke _data ,  
			
				
				
			
		
	
		
		
			
				
					
					        gl . enableVertexAttribArray ( pr . locations [ 'a_stroke_id' ] ) ;             context . dynamic _stroke _count ,   
			
				
				
			
		
	
		
		
			
				
					
					        gl . enableVertexAttribArray ( pr . locations [ 'a_pressure' ] ) ;         ) ;  
			
				
				
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        // Points (a, b) and stroke ids are stored in separate cpu buffers so that points can be reused (look at stride and offset values)
  
			
		
	
		
		
			
				
					
					        if  ( context . dynamic _instance _ids . size  >  1 )  {  
			
		
	
		
		
			
				
					
					            gl . vertexAttribPointer ( pr . locations [ 'a_a' ] ,           2 ,  gl . FLOAT ,          false ,  2  *  4 ,  0 ) ;  
			
		
	
		
		
			
				
					
					            gl . vertexAttribPointer ( pr . locations [ 'a_b' ] ,           2 ,  gl . FLOAT ,          false ,  2  *  4 ,  2  *  4 ) ;  
			
		
	
		
		
			
				
					
					        }  else  {  
			
		
	
		
		
			
				
					
					            // A special case where there is no second point. Reuse the first point and handle the zero length segment in the shader
  
			
		
	
		
		
			
				
					
					            gl . vertexAttribPointer ( pr . locations [ 'a_a' ] ,           2 ,  gl . FLOAT ,          false ,  2  *  4 ,  0 ) ;  
			
		
	
		
		
			
				
					
					            gl . vertexAttribPointer ( pr . locations [ 'a_b' ] ,           2 ,  gl . FLOAT ,          false ,  2  *  4 ,  0 ) ;  
			
		
	
		
		
			
				
					
					        }  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . vertexAttribIPointer ( pr . locations [ 'a_stroke_id' ] ,  1 ,  gl . INT ,                   4 ,  context . dynamic _instance _points . size  *  4 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribPointer ( pr . locations [ 'a_pressure' ] ,    2 ,  gl . UNSIGNED _BYTE ,  true ,   1 ,  context . dynamic _instance _points . size  *  4  +  context . dynamic _instance _ids . size  *  4 ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_a' ] ,  1 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_b' ] ,  1 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_stroke_id' ] ,  1 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_pressure' ] ,  1 ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . drawArraysInstanced ( gl . TRIANGLES ,  0 ,  32  *  3  +  6  +  32  *  3 ,  dynamic _segment _count ) ;  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_a' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_b' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_stroke_id' ] ,  0 ) ;  
			
		
	
		
		
			
				
					
					        gl . vertexAttribDivisor ( pr . locations [ 'a_pressure' ] ,  0 ) ;  
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					    }     }  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    // HUD: resize handles, etc
     // HUD: resize handles, etc