include "inc/cmdsys.plh"
include "inc/int32.plh"
include "inc/sincos.plh"

const CLIP_LEFT   = 1
const CLIP_RIGHT  = 2
const CLIP_TOP    = 4
const CLIP_BOTTOM = 8

var turtleXp4, turtleYp4, turtleAngle
byte pen
var clipLeft, clipRight, clipTop, clipBottom
var drawLine

def clipCode(x, y)#1
    byte xcode, ycode

    if x < clipLeft
        xcode = CLIP_LEFT
    elsif x > clipRight
        xcode = CLIP_RIGHT
    else
        xcode = 0
    fin
    if y < clipTop
        ycode = CLIP_TOP
    elsif y > clipBottom
        ycode = CLIP_BOTTOM
    else
        ycode = 0
    fin
    return xcode | ycode
end

def lerp(a1, b1, a2, b2, n)#1
    word[2] i32

    if b2 == b1; return b1; fin // Horizontal lerp
    if a2 == a1; return n;  fin // Vertical lerp
    loadi16(b2 - b1)
    muli16(n - a1)
    divi16(a2 - a1)
    store32(@i32)
    return i32[0] + b1
end

export def clipLine(x1, y1, x2, y2)#0
    byte outcode1, outcode2

    outcode1 = clipCode(x1, y1)
    outcode2 = clipCode(x2, y2)
    if outcode1 & outcode2; return; fin // Early exit - clipped away
    if outcode1 | outcode2 // Something is getting clipped
        if outcode1 & CLIP_LEFT
            y1 = lerp(x1, y1, x2, y2, clipLeft)
            x1 = clipLeft
            outcode1 = clipCode(x1, y1)
        elsif outcode1 & CLIP_RIGHT
            y1 = lerp(x1, y1, x2, y2, clipRight)
            x1 = clipRight
            outcode1 = clipCode(x1, y1)
        fin
        if outcode1 & CLIP_TOP
            x1 = lerp(y1, x1, y2, x2, clipTop)
            y1 = clipTop
            outcode1 = clipCode(x1, y1)
        elsif outcode1 & CLIP_BOTTOM
            x1 = lerp(y1, x1, y2, x2, clipBottom)
            y1 = clipBottom
            outcode1 = clipCode(x1, y1)
        fin
        if outcode2 & CLIP_LEFT
            y2 = lerp(x1, y1, x2, y2, clipLeft)
            x2 = clipLeft
            outcode2 = clipCode(x2, y2)
        elsif outcode2 & CLIP_RIGHT
            y2 = lerp(x1, y1, x2, y2, clipRight)
            x2 = clipRight
            outcode2 = clipCode(x2, y2)
        fin
        if outcode2 & CLIP_TOP
            x2 = lerp(y1, x1, y2, x2, clipTop)
            y2 = clipTop
            outcode2 = clipCode(x2, y2)
        elsif outcode2 & CLIP_BOTTOM
            x2 = lerp(y1, x1, y2, x2, clipBottom)
            y2 = clipBottom
            outcode2 = clipCode(x2, y2)
        fin
        if outcode1 | outcode2; return; fin // Clipped away
    fin
    drawLine(x1, y1, x2, y2)#0
end

export def clipRect(left, top, right, bottom)#0
    clipLeft   = left
    clipTop    = top
    clipRight  = right
    clipBottom = bottom
end

export def initTurtle(width, height, linefunc)#0
    drawLine     = linefunc
    clipRect(0, 0, width - 1, height - 1)
    turtleXp4    = width << 3
    turtleYp4    = height << 3
    turtleAngle  = 0
    pen          = 1
end

export def turnTo(angle)#0
    turtleAngle = angle
    while turtleAngle >= 360; turtleAngle = turtleAngle - 360; loop
    while turtleAngle < 0; turtleAngle = turtleAngle + 360; loop
end

export def turn(angle)#0
    turnTo(turtleAngle + angle)
end

export def moveTo(x, y)#0
    if pen
        clipLine(turtleXp4 >> 4, turtleYp4 >> 4, x, y)
    fin
    turtleXp4 = x << 4
    turtleYp4 = y << 4
end

export def move(dist)#0
    var oldX, oldY

    oldX      = turtleXp4 >> 4
    oldY      = turtleYp4 >> 4
    turtleXp4 = turtleXp4 + mulcos(dist << 4, turtleAngle)
    turtleYp4 = turtleYp4 + mulsin(dist << 4, turtleAngle)
    if pen
        clipLine(turtleXp4 >> 4, turtleYp4 >> 4, oldX, oldY)
    fin
end

export def movep4(distp4)#0
    var oldX, oldY

    oldX      = turtleXp4 >> 4
    oldY      = turtleYp4 >> 4
    turtleXp4 = turtleXp4 + mulcos(distp4, turtleAngle)
    turtleYp4 = turtleYp4 + mulsin(distp4, turtleAngle)
    if pen
        clipLine(turtleXp4 >> 4, turtleYp4 >> 4, oldX, oldY)
    fin
end

export def penUp#0
    pen = 0
end

export def penDown#0
    pen = 1
end

//
// Keep module in memory
//
return modkeep
done
