--------------------------------------------------------------------------- -- begin stroke library --------------------------------------------------------------------------- _gStrokeNum = 0 function bezier( b1, b2, b3, b4, t ) local ti = (1.0 - t); local p0 = ti * ti * ti * b1 local p1 = 3*t * ti*ti * b2 local p2 = 3*t*t * ti * b3 local p3 = t*t*t * b4 return p0 + p1 + p2 + p3 end function normalize( x, y ) local dist = bs_distance( x, y ) if dist == 0 then return x,y end return x/dist, y/dist end function stroke_pos( pts, idx ) if idx < 1 then local vx1 = pts[1].x - pts[2].x local vy1 = pts[1].y - pts[2].y local vx2 = pts[2].x - pts[3].x local vy2 = pts[2].y - pts[3].y local a1 = bs_atan( vx1, vy1 ) local a2 = bs_atan( vx2, vy2 ) local adif = a1 - a2 local x,y = bs_rotate( vx1, vy1, adif ) return pts[1].x + x, pts[1].y + y end local s = _gStrokeNum if idx > s then local vx1 = pts[s].x - pts[s-1].x local vy1 = pts[s].y - pts[s-1].y local vx2 = pts[s-1].x - pts[s-2].x local vy2 = pts[s-1].y - pts[s-2].y local a1 = bs_atan( vx1, vy1 ) local a2 = bs_atan( vx2, vy2 ) local adif = a1 - a2 local x,y = bs_rotate( vx1, vy1, adif ) return pts[s].x + x, pts[s].y + y end return pts[idx].x, pts[idx].y end function stroke_width( pts, idx ) if idx < 1 then return pts[1].w end local s = _gStrokeNum if idx > s then return pts[s].w end return pts[idx].w end function stroke_interpolate( pts, t ) local idx = math.floor( t ) local f = t - idx local px4,py4 = stroke_pos( pts, idx+2 ) local px3,py3 = stroke_pos( pts, idx+1 ) local px2,py2 = stroke_pos( pts, idx+0 ) local px1,py1 = stroke_pos( pts, idx-1 ) local vx2 = px4 - px2 local vy2 = py4 - py2 local vx1 = px3 - px1 local vy1 = py3 - py1 local len = bs_distance( px3-px2, py3-py2 ) local m = 0.35 vx1,vy1 = normalize( vx1, vy1 ) vx1 = vx1 * len * m vy1 = vy1 * len * m vx2,vy2 = normalize( vx2, vy2 ) vx2 = vx2 * len * m vy2 = vy2 * len * m local cx1 = pts[idx].x + vx1 local cy1 = pts[idx].y + vy1 local cx2 = pts[idx+1].x - vx2 local cy2 = pts[idx+1].y - vy2 local x = bezier( px2, cx1, cx2, px3, f ) local y = bezier( py2, cy1, cy2, py3, f ) local w1 = stroke_width( pts, idx ) local w2 = stroke_width( pts, idx+1 ) local w = w1 + (w2 - w1) * f return x,y,w end function stroke_normal( x_, x, y_, y, w ) local nx = x_ - x local ny = y_ - y nx,ny = normalize( nx, ny ) nx,ny = bs_rotate( nx, ny, 3.14159/2 ) return nx*w/2, ny*w/2 end function stroke_subdiv( pts, idx ) local x1,y1,w1 = stroke_interpolate( pts, idx + 0.0 ) local x2,y2,w2 = stroke_interpolate( pts, idx + 0.25 ) local x3,y3,w3 = stroke_interpolate( pts, idx + 0.50 ) local x4,y4,w4 = stroke_interpolate( pts, idx + 0.75 ) local x5,y5,w5 = stroke_interpolate( pts, idx + 0.999 ) local dist = 0 dist = dist + bs_distance( x2-x1, y2-y1 ) dist = dist + bs_distance( x3-x2, y3-y2 ) dist = dist + bs_distance( x4-x3, y4-y3 ) dist = dist + bs_distance( x5-x4, y5-y4 ) local subdiv = dist / 4 if subdiv < 16 then subdiv = 16 end if subdiv > 128 then subdiv = 128 end return subdiv end function stroke_add( pts, x, y, w ) local idx = _gStrokeNum + 1 pts[idx] = {} pts[idx].x = x pts[idx].y = y pts[idx].w = w _gStrokeNum = _gStrokeNum + 1 end function stroke_set( pts ) local s = _gStrokeNum if s < 3 then return end local x,y,w = stroke_interpolate( pts, 1 ) local x_,y_,w_ = stroke_interpolate( pts, 1 + 0.0001 ) local nx,ny = stroke_normal( x_, x, y_, y, w ) bs_polygon( pts[1].x + nx, pts[1].y + ny ) -- side 1 local i,j for i=1,s-1 do local subdiv = math.floor( stroke_subdiv( pts, i ) ) for j=1,subdiv-1 do x,y,w = stroke_interpolate( pts, i + j/subdiv ) x_,y_,w_ = stroke_interpolate( pts, i + j/subdiv + 1/1000 ) nx,ny = stroke_normal( x_, x, y_, y, w ) bs_polygon( x + nx, y + ny ) end end x,y,w = stroke_interpolate( pts, s-1 + 0.999 ) x_,y_,w_ = stroke_interpolate( pts, s-1 + 0.9991 ) nx,ny = stroke_normal( x_, x, y_, y, w ) bs_polygon( pts[s].x + nx, pts[s].y + ny ) -- side 2 bs_polygon( pts[s].x - nx, pts[s].y - ny ) for i=1,s-1 do local idx = s+1 - i local subdiv = math.floor( stroke_subdiv( pts, idx-1 ) ) for j=1,subdiv-1 do x,y,w = stroke_interpolate( pts, idx - j/subdiv ) x_,y_,w_ = stroke_interpolate( pts, idx - j/subdiv - 1/1000 ) nx,ny = stroke_normal( x_, x, y_, y, w ) bs_polygon( x + nx, y + ny ) end end x,y,w = stroke_interpolate( pts, 1 + 0.001 ) x_,y_,w_ = stroke_interpolate( pts, 1 ) nx,ny = stroke_normal( x_, x, y_, y, w ) bs_polygon( pts[1].x + nx, pts[1].y + ny ) _gStrokeNum = 0 end --------------------------------------------------------------------------- -- end stroke library --------------------------------------------------------------------------- function param1() return "color rnd", 0, 100, 40 end function main( x, y, p ) local w = bs_width() if w < 10 then w = 10 end if not firstDraw then local distance = bs_distance( lastDrawX - x, lastDrawY - y ) if distance < w*1.5 then return 0 end end local dx,dy = bs_dir() local pts = {} local i for i=0,4 do stroke_add( pts, 0, (0.5 - math.random()) * w * 2, 0 ) stroke_add( pts, w*2, (0.5 - math.random()) * w * 2, w/5 ) stroke_add( pts, w*4, (0.5 - math.random()) * w * 2, w/5 ) stroke_add( pts, w*6, (0.5 - math.random()) * w * 2, 0 ) stroke_set( pts ) bs_polygon_move_center() bs_polygon_move( (0.5 - math.random()) * w * 3, 0 ) bs_polygon_rotate( bs_atan( dx, dy ) ) bs_polygon_move( x, y ) local r,g,b = bs_forebg( 1.0 - math.random()*bs_param1()/100 ) bs_fill( r,g,b, 255 ) end lastDrawX = x lastDrawY = y firstDraw = false return 1 end lastDrawX = 0 lastDrawY = 0 firstDraw = true