@ -1,42 +1,25 @@
				@@ -1,42 +1,25 @@
					 
			
		
	
		
			
				
					function  push _stroke ( s ,  stroke ,  stroke _index )  {  
			
		
	
		
			
				
					    const  points  =  stroke . points ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( points . length  <  2 )  {  
			
		
	
		
			
				
					        return ;  
			
		
	
		
			
				
					    }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    for  ( let  i  =  0 ;  i  <  points . length  -  1 ;  ++ i )  {  
			
		
	
		
			
				
					        const  from  =  points [ i ] ;  
			
		
	
		
			
				
					        const  to  =  points [ i  +  1 ] ;  
			
		
	
		
			
				
					         
			
		
	
		
			
				
					        ser _f32 ( s ,  from . x ) ;  
			
		
	
		
			
				
					        ser _f32 ( s ,  from . y ) ;  
			
		
	
		
			
				
					        ser _f32 ( s ,  to . x ) ;  
			
		
	
		
			
				
					        ser _f32 ( s ,  to . y ) ;  
			
		
	
		
			
				
					        ser _u32 ( s ,  stroke _index ) ;  
			
		
	
		
			
				
					    }  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					function  geometry _prepare _stroke ( state )  {  
			
		
	
		
			
				
					    if  ( ! state . online )  {  
			
		
	
		
			
				
					        return  null ;  
			
		
	
		
			
				
					    }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( state . players [ state . me ] . points . length  ===  0 )  {  
			
		
	
		
			
				
					    const  player  =  state . players [ state . me ] ;  
			
		
	
		
			
				
					    const  stroke  =  player . strokes [ player . strokes . length  -  1 ] ;  // MY OWN player.strokes should never be bigger than 1 element
  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( stroke . points . length  ===  0 )  {  
			
		
	
		
			
				
					        return  null ;  
			
		
	
		
			
				
					    }      
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    const  points  =  process _stroke2 ( state . canvas . zoom ,  state . players [ state . me ]  . points ) ;   
			
		
	
		
			
				
					    const  points  =  process _stroke2 ( state . canvas . zoom ,  stroke . points ) ;   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    return  {  
			
		
	
		
			
				
					        'color' :  state . players [ state . me ]  . color ,  
			
		
	
		
			
				
					        'width' :  state . players [ state . me ]  . width ,  
			
		
	
		
			
				
					        'color' :  stroke . color ,  
			
		
	
		
			
				
					        'width' :  stroke . width ,  
			
		
	
		
			
				
					        'points' :  points ,  
			
		
	
		
			
				
					        'user_id' :  state . me ,  
			
		
	
		
			
				
					    } ;  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					async  function  geometry _write _instances ( state ,  context ,  callback )  {  
			
		
	
		
			
				
					    state . stats . rdp _max _count  =  0 ;  
			
		
	
		
			
				
					    state . stats . rdp _segments  =  0 ;  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -56,6 +39,7 @@ function geometry_add_dummy_stroke(context) {
				@@ -56,6 +39,7 @@ function geometry_add_dummy_stroke(context) {
					 
			
		
	
		
			
				
					    ser _u16 ( context . stroke _data ,  0 ) ;  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					// Real stroke, add forever
  
			
		
	
		
			
				
					function  geometry _add _stroke ( state ,  context ,  stroke ,  stroke _index ,  skip _bvh  =  false )  {  
			
		
	
		
			
				
					    if  ( ! state . online  ||  ! stroke  ||  stroke . coords _to  -  stroke . coords _from  ===  0  ||  stroke . deleted )  return ;  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -83,9 +67,11 @@ function recompute_dynamic_data(state, context) {
				@@ -83,9 +67,11 @@ function recompute_dynamic_data(state, context) {
					 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    for  ( const  player _id  in  state . players )  {  
			
		
	
		
			
				
					        const  player  =  state . players [ player _id ] ;  
			
		
	
		
			
				
					        if  ( player . points . length  >  0 )  {  
			
		
	
		
			
				
					            total _points  +=  player . points . length ;  
			
		
	
		
			
				
					            total _strokes  +=  1 ;  
			
		
	
		
			
				
					        for  ( const  stroke  of  player . strokes )  {  
			
		
	
		
			
				
					            if  ( ! stroke . empty  &&  stroke . points . length  >  0 )  {  
			
		
	
		
			
				
					                total _points  +=  stroke . points . length ;  
			
		
	
		
			
				
					                total _strokes  +=  1 ;  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					    }  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -106,44 +92,69 @@ function recompute_dynamic_data(state, context) {
				@@ -106,44 +92,69 @@ function recompute_dynamic_data(state, context) {
					 
			
		
	
		
			
				
					        // player has the same data as their current stroke: points, color, width
  
			
		
	
		
			
				
					        const  player  =  state . players [ player _id ] ;  
			
		
	
		
			
				
					     
			
		
	
		
			
				
					        for  ( let  i  =  0 ;  i  <  player . points . length ;  ++ i )  {  
			
		
	
		
			
				
					            const  p  =  player . points [ i ] ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            tv _add ( context . dynamic _instance _points ,  p . x ) ;  
			
		
	
		
			
				
					            tv _add ( context . dynamic _instance _points ,  p . y ) ;  
			
		
	
		
			
				
					            tv _add ( context . dynamic _instance _pressure ,  p . pressure ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            if  ( i  !==  player . points . length  -  1 )  {  
			
		
	
		
			
				
					                tv _add ( context . dynamic _instance _ids ,  stroke _index ) ;  
			
		
	
		
			
				
					            }  else  {  
			
		
	
		
			
				
					                tv _add ( context . dynamic _instance _ids ,  stroke _index  |  ( 1  <<  31 ) ) ;  
			
		
	
		
			
				
					        for  ( const  stroke  of  player . strokes )  {  
			
		
	
		
			
				
					            if  ( ! stroke . empty  &&  stroke . points . length  >  0 )  {  
			
		
	
		
			
				
					                for  ( let  i  =  0 ;  i  <  stroke . points . length ;  ++ i )  {  
			
		
	
		
			
				
					                    const  p  =  stroke . points [ i ] ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                    tv _add ( context . dynamic _instance _points ,  p . x ) ;  
			
		
	
		
			
				
					                    tv _add ( context . dynamic _instance _points ,  p . y ) ;  
			
		
	
		
			
				
					                    tv _add ( context . dynamic _instance _pressure ,  p . pressure ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                    if  ( i  !==  stroke . points . length  -  1 )  {  
			
		
	
		
			
				
					                        tv _add ( context . dynamic _instance _ids ,  stroke _index ) ;  
			
		
	
		
			
				
					                    }  else  {  
			
		
	
		
			
				
					                        tv _add ( context . dynamic _instance _ids ,  stroke _index  |  ( 1  <<  31 ) ) ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                const  color _u32  =  stroke . color ;  
			
		
	
		
			
				
					                const  r  =  ( color _u32  >>  16 )  &  0xFF ;  
			
		
	
		
			
				
					                const  g  =  ( color _u32  >>  8 )  &  0xFF ;  
			
		
	
		
			
				
					                const  b  =  color _u32  &  0xFF ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                ser _u16 ( context . dynamic _stroke _data ,  r ) ;  
			
		
	
		
			
				
					                ser _u16 ( context . dynamic _stroke _data ,  g ) ;  
			
		
	
		
			
				
					                ser _u16 ( context . dynamic _stroke _data ,  b ) ;  
			
		
	
		
			
				
					                ser _u16 ( context . dynamic _stroke _data ,  stroke . width ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                stroke _index  +=  1 ;  // TODO: proper player Z order
  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					         
			
		
	
		
			
				
					        if  ( player . points . length  >  0 )  {  
			
		
	
		
			
				
					            const  color _u32  =  player . color ;  
			
		
	
		
			
				
					            const  r  =  ( color _u32  >>  16 )  &  0xFF ;  
			
		
	
		
			
				
					            const  g  =  ( color _u32  >>  8 )  &  0xFF ;  
			
		
	
		
			
				
					            const  b  =  color _u32  &  0xFF ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            ser _u16 ( context . dynamic _stroke _data ,  r ) ;  
			
		
	
		
			
				
					            ser _u16 ( context . dynamic _stroke _data ,  g ) ;  
			
		
	
		
			
				
					            ser _u16 ( context . dynamic _stroke _data ,  b ) ;  
			
		
	
		
			
				
					            ser _u16 ( context . dynamic _stroke _data ,  player . width ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            stroke _index  +=  1 ;  // TODO: proper player Z order
  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					    }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    context . dynamic _segment _count  =  total _points ;  
			
		
	
		
			
				
					    context . dynamic _stroke _count  =  total _strokes ;  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					function  geometry _add _point  ( state ,  context ,  player _id ,  point ,  is _pen ,  raw  =  false )  {  
			
		
	
		
			
				
					function  geometry _start _prestroke ( state ,  player _id )  {  
			
		
	
		
			
				
					    if  ( ! state . online )  return ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    const  player  =  state . players [ player _id ] ;      
			
		
	
		
			
				
					    const  points  =  player . points ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    player . strokes . push ( {  
			
		
	
		
			
				
					        'empty' :  false ,  
			
		
	
		
			
				
					        'points' :  [ ] ,  
			
		
	
		
			
				
					        'head' :  null ,  
			
		
	
		
			
				
					        'color' :  player . color ,  
			
		
	
		
			
				
					        'width' :  player . width ,  
			
		
	
		
			
				
					    } ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    player . current _prestroke  =  true ;  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					function  geometry _end _prestroke ( state ,  player _id )  {  
			
		
	
		
			
				
					    if  ( ! state . online )  return ;  
			
		
	
		
			
				
					    const  player  =  state . players [ player _id ] ;      
			
		
	
		
			
				
					    player . current _prestroke  =  false ;   
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					function  geometry _add _prepoint ( state ,  context ,  player _id ,  point ,  is _pen ,  raw  =  false )  {  
			
		
	
		
			
				
					    if  ( ! state . online )  return ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    const  player  =  state . players [ player _id ] ;  
			
		
	
		
			
				
					    const  stroke  =  player . strokes [ player . strokes . length  -  1 ] ;  
			
		
	
		
			
				
					    const  points  =  stroke . points ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( point . pressure  <  config . min _pressure )  {  
			
		
	
		
			
				
					        point . pressure  =  config . min _pressure ;  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -152,30 +163,35 @@ function geometry_add_point(state, context, player_id, point, is_pen, raw = fals
				@@ -152,30 +163,35 @@ function geometry_add_point(state, context, player_id, point, is_pen, raw = fals
					 
			
		
	
		
			
				
					    if  ( points . length  >  0  &&  ! raw )  {  
			
		
	
		
			
				
					        // pulled from "perfect-freehand" package. MIT
  
			
		
	
		
			
				
					        // https://github.com/steveruizok/perfect-freehand/
  
			
		
	
		
			
				
					        const  streamline  =  0.5 ;  
			
		
	
		
			
				
					        const  streamline  =  0.7 5 ;  
			
		
	
		
			
				
					        const  t  =  0.15  +  ( 1  -  streamline )  *  0.85  
			
		
	
		
			
				
					        const  smooth _pressure  =  exponential _smoothing ( points ,  point ,  3 ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        points . push ( {  
			
		
	
		
			
				
					            'x' :  player . dynamic _ head. x  *  t  +  point . x  *  ( 1  -  t ) ,  
			
		
	
		
			
				
					            'y' :  player . dynamic _ head. y  *  t  +  point . y  *  ( 1  -  t ) ,  
			
		
	
		
			
				
					            'pressure' :  is _pen  ?  player . dynamic _ head. pressure  *  t  +  smooth _pressure  *  ( 1  -  t )  :  point . pressure ,  
			
		
	
		
			
				
					            'x' :  stroke . head . x  *  t  +  point . x  *  ( 1  -  t ) ,  
			
		
	
		
			
				
					            'y' :  stroke . head . y  *  t  +  point . y  *  ( 1  -  t ) ,  
			
		
	
		
			
				
					            'pressure' :  is _pen  ?  stroke . head . pressure  *  t  +  smooth _pressure  *  ( 1  -  t )  :  point . pressure ,  
			
		
	
		
			
				
					        } ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        if  ( is _pen )  {  
			
		
	
		
			
				
					            point . pressure  =  smooth _pressure ;  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					    }  else  {  
			
		
	
		
			
				
					        state . players [ player _id ] . points . push ( point ) ;  
			
		
	
		
			
				
					        points . push ( point ) ;  
			
		
	
		
			
				
					    }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    stroke . head  =  point ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    recompute _dynamic _data ( state ,  context ) ;  
			
		
	
		
			
				
					    player . dynamic _head  =  point ;  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					function  geometry _clear _player ( state ,  context ,  player _id )  {  
			
		
	
		
			
				
					// Remove prestroke from dynamic data (usually because it's now a real stroke)
  
			
		
	
		
			
				
					function  geometry _clear _oldest _prestroke ( state ,  context ,  player _id )  {  
			
		
	
		
			
				
					    if  ( ! state . online )  return ;  
			
		
	
		
			
				
					    state . players [ player _id ] . points . length  =  0 ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    const  player  =  state . players [ player _id ] ;  
			
		
	
		
			
				
					    player . strokes . shift ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    recompute _dynamic _data ( state ,  context ) ;  
			
		
	
		
			
				
					}