-- lua script for drawing spirographs
-- some basic constants
local abort = false
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: Radius 2, 60
--@TBCONFIG SLIDER: Bendyness, 15
--@TBCONFIG SLIDER: Revolutions, 12
--@TBCONFIG SLIDER: XYDistortion, 50
--@TBCONFIG SLIDER: Radius 3, 25
--@TBCONFIG SLIDER: Radius 3 Scale, 50

--@TBCONFIG STYLE: Number of Wheels, 1,2,3

--@TBCONFIG FLAG: Inner Outer R, true
--@TBCONFIG FLAG: Revolutions * 3, false
--@TBCONFIG FLAG: Paint, false

local ucenterX = math.floor(0.5 * width)
local ucenterY = math.floor(0.5 * height)
local uradius1 = 1  

local uradius2 = sliderVal1 * uradius1 * 2
local bendyness = sliderVal2 - 0.5
local revolutions = sliderVal3 * math.pi * 100
local distortion = sliderVal4 
local uradius3 = sliderVal5 * uradius2 * 2 
local R3Scale = sliderVal6 

local InnerOuterR = flagVal1
if flagVal2 == true then revolutions =revolutions * 3 end 
local uPaint = flagVal3

local r3 = false
if styleVal1 == 2 then r3 = true end
-- ------------------------------
-- 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  
        set_rgba(pointx, pointy, r, g, b, 1)
    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

r, g, b = get_color1()


local current_x = 1e+10
local current_y = 1e+10
local new_x, new_y
local o, t 
local bScale = 6

local ScaleFactor  = screen_radius * 0.5  / ( 1.0 + math.abs(bendyness) * 3)
bendyness = bendyness * 6 

if InnerOuterR then
    uradius2 = -uradius2
end 

local r1r2 = (1 - uradius2) / uradius2
local r2r3 = (1 - uradius2) / uradius3
paint_open(1)
    for  t = 0, revolutions , 0.01 do 
		if (is_escape() > 0) then
			abort = true;break
		end
        new_x =   math.cos(t) + distortion * bendyness * math.cos(r1r2 * t) 
        new_y =   math.sin(t) - (1 - distortion) * bendyness * math.sin(r1r2 * t) 
        if r3 then 
            new_x =   new_x +  R3Scale * math.cos(r2r3 * t) 
            new_y =   new_y - R3Scale * math.sin(r2r3 * t)
        else

        end
        -- relocate to center of screen    
        new_x = ScaleFactor * new_x + w_mid
        new_y = ScaleFactor * new_y + h_mid
        -- handle starting position
        if current_x == 1e+10 then 
		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

paint_close()






