-- lua script for drawing stars
-- some basic constants
local w_mid = width / 2
local h_mid = height / 2
local screen_radius = math.sqrt((w_mid * w_mid) + (h_mid * h_mid))
local r2d = 180 / 3.14159265
local r, g, b

-- allow the user to change the settings.
-- Note the sliders have range is 0 .. ", " .. 1.0 for reading but have range 1..100 for setting
--@TBCONFIG SLIDER: No of Points, 50
--@TBCONFIG SLIDER: Extrusion, 20
--@TBCONFIG SLIDER: Twist, 50
--@TBCONFIG SLIDER: Bendyness,50
--@TBCONFIG SLIDER: Scale, 50
--@TBCONFIG SLIDER: Rotation, 0
--@TBCONFIG FLAG: Bendy Lines, false
--@TBCONFIG FLAG: Paint, false
--@TBCONFIG STYLE: Bend Mode, 1,Square Law, Linear, reciprocal

local uNoOfPoints = math.floor(sliderVal1 * 23) + 3
local uExtrusion = sliderVal2 * 1.95
local uTwist = (sliderVal3 - 0.5) * math.pi * 2
local uBendyness = (sliderVal4 - 0.33) * 6
local uScale = sliderVal5 * screen_radius
local uRotation = sliderVal6 * math.pi * 2 / uNoOfPoints
local thickness = 1
local uBendy = false
local uPaint = false
if flagVal1 == true then uBendy = true end
if flagVal2 == true then uPaint = true end
local WeightMode = styleVal1
-- ------------------------------
-- note: functions must be defined BEFORE the calling logic calls them
-- ------------------------------

function plot(pointx,pointy)
	if (pointx > 0) and (pointy > 0) and (pointx < width) and (pointy < height) then
		local xx = pointx - thickness - 1
		local yy = pointy - thickness - 1
		local x
		local y
		for xi = 1, thickness do
		x = xx + xi
			for yi = 1, thickness do
			y = yy + yi
			set_rgba(x, y, r, g, b, 1)
			end
		end
	end
end
function round(x)
local xf = math.floor(x)
	if (x - xf) <= 0.5 then
		return xf
	else
		return math.ceil(x)
	end
end

-- Line Clipping Algorithm -- Liang-Barsky
function Liang_Barsky_clipTest(p, q, u1, u2)
local r
	if (p < 0) then
		r = q / p
		if (r > u2) then
			return 0, u1, u2
		elseif (r > u1) then
			return 1, r, u2
		end
	elseif (p > 0) then
		r = q / p
		if (r < u1) then
			return 0, u1, u2
		elseif (r < u2) then
			return 1, u1, r
		end
	elseif (q < 0) then
		return 0, u1, u2
	end
return 1, u1, u2
end
function Liang_Barsky_clipping(x0, y0, x1, y1)
local XS_MIN = 0
local XS_MAX = width
local YS_MIN = 0
local YS_MAX = height
local dx = x1 - x0
local dy = y1 - y0
local u1 = 0
local u2 = 1
local t1, t2, t3, t4

t1, u1, u2 = Liang_Barsky_clipTest(-dx, x0-XS_MIN, u1, u2)
t2, u1, u2 = Liang_Barsky_clipTest( dx, XS_MAX-x0, u1, u2)
t3, u1, u2 = Liang_Barsky_clipTest(-dy, y0-YS_MIN, u1, u2)
t4, u1, u2 = Liang_Barsky_clipTest( dy, YS_MAX-y0, u1, u2)

if (t1 == 1) and (t2 == 1) and (t3 == 1) and (t4 == 1) then
	if (u2 < 1) then
		x1 = x0 + round(u2 * dx)
		y1 = y0 + round(u2 * dy)
	end
	if (u1 > 0) then
		x0 = x0 + round(u1 * dx)
		y0 = y0 + round(u1 * dy)
	end
end
return x0, y0, x1, y1
end
-- Line Generating Algorithm using Bresenham's technique
function line_bres(x0, y0, x1, y1)
x0, y0, x1, y1 = Liang_Barsky_clipping(x0, y0, x1, y1)
local steep, t
	if (math.abs(y1 - y0) > math.abs(x1 - x0)) then
		steep = 1
	else
		steep = 0
	end

	if steep == 1 then
		t = x0; x0 = y0; y0 = t
		t = x1; x1 = y1; y1 = t
	end
if x0 > x1 then
t = x0; x0 = x1; x1 = t
t = y0; y0 = y1; y1 = t
end

local deltax = x1 - x0
local deltay = math.abs(y1 - y0)
local error = round(deltax / 2)
local ystep
local y = y0
	if y0 < y1 then ystep = 1 else ystep = -1 end

	for x = x0, x1 do
		if (steep == 1) then plot(y,x) else plot(x,y) end
		error = error - deltay
		if error < 0 then
			y = y + ystep
			error = error + deltax
		end
	end
end
function LineIntersection(x1, y1, x2, y2, u1, v1, u2, v2)
	local b1 = (y2 - y1) / (x2 - x1)  --  slope of first line
	local b2 = (v2 - v1) / (u2 - u1)  --  slope of second line
	local a1 = y1 - b1 * x1 
	local a2 = v1 - b2 * u1 
	local xi =  -  (a1 - a2) / (b1 - b2)
	local yi = a1 + b1 * xi 
	return true,  xi,  yi 
	-- if (x1 - xi) * (xi - x2) >= 0 
		-- and (u1 - xi) * (xi - u2) >= 0 
		-- and (y1 - yi) * (yi - y2) >= 0 
		-- and (v1 - yi) * (yi - v2)>=0 then 
		-- return true,  xi,  yi 
	-- else 
		-- return false,  0,  0
	-- end 
end
function Interpolate(x1,y1,x2,y2,n, nMax)
	local xi = x1 + (x2 - x1) * n / nMax
	local yi = y1 + (y2 - y1) * n / nMax
	return xi,yi
end
function Weighting(step, MaxSteps)
local range = math.abs((step / MaxSteps - 0.5) * 2)   -- basic range is +1 .. 0 .. +1
local s 
	if WeightMode == 1 then 
		s = 1 - range * range   -- default is squared (parabola)
	elseif  WeightMode == 2 then 
		s = 1 - range		-- gives range as   0   ..  1  ..  0
	elseif WeightMode == 3 then
		s = (1 / (range  + 1 ) )  - 1
	end
	return s
end

r, g, b = get_color1()
paint_open(1)

local x1,x2,x3,y1,y2,y3,n,t1, t2, t3
local w1 = width / 2
local h1 = height / 2
local sectorAngle = math.pi * 2 / uNoOfPoints
local sectorAngleHalf = sectorAngle / 2
local Correction = math.cos(sectorAngleHalf)
local step
local MaxSteps = 100
local current_x = 1e+10
local current_y = 1e+10
local start_x, start_y, new_x,new_y,u1,v1,u2,v2,a,p1,p2
for n = 0, uNoOfPoints - 1 do
	-- start point
	t1 = sectorAngle * n + uRotation
	x1 = math.cos(t1) * uScale + w1
	y1 = math.sin(t1)  * uScale + h1

	-- middle point - with no correction for bendyness
	t2 = sectorAngle * (n + 0.5) + uRotation + uTwist
	x2 = math.cos(t2) * uExtrusion * Correction * uScale + w1
	y2 = math.sin(t2) * uExtrusion * Correction * uScale + h1
	
	-- end point
	t3 = sectorAngle * (n + 1) + uRotation
	x3 = math.cos(t3) * uScale + w1
	y3 = math.sin(t3) * uScale + h1
	
	if uBendy == false then 
		if  uPaint == false  then
			line_bres(x1 , y1 , x2 , y2 )
			line_bres(x2 , y2 , x3 , y3 )
		else
			paint_line(x1 , y1 , x2 , y2 )
			paint_line(x2 , y2 , x3 , y3 )
		end
	else
	-- for uBendyness we need to draw a curve from x1 to x3 via x2 where we hit x2 if uBendyness = 0 and remain close to x1,x2 if uBendyness = 1
		for step = 0, MaxSteps - 1 do
			u1,v1 = Interpolate(x1,y1,x2,y2,step,MaxSteps )
			u2,v2 = Interpolate(x2,y2,x3,y3,step,MaxSteps )
			a,p1,p2 = LineIntersection(x1,y1,u2,v2,x3,y3,u1,v1)
			new_x,new_y = Interpolate(p1,p2,x2,y2, Weighting(step, MaxSteps) * uBendyness, 1)
			if current_x == 1e+10 then 
				start_x = new_x; start_y = new_y
			else
				if uPaint == false  then
					line_bres(current_x, current_y, new_x, new_y)
				else
					paint_line(current_x, current_y, new_x, new_y)
				end 
	        end
	        current_x = new_x
	        current_y = new_y
		end

	end

end
	if uBendy == true then 
		if uPaint == false  then
			line_bres( new_x, new_y, start_x, start_y)
		else
			paint_line( new_x, new_y, start_x, start_y)
		end 
	end
paint_close()
