-- global temp. variables for the polyfiller
local tmp_left1=  vec(0,0,0,0,0,0,0,0) -- x,y,z, u1,v1, u2,v2, dummy
local tmp_left2=  vec(0,0,0,0,0,0,0,0)
local tmp_right1= vec(0,0,0,0,0,0,0,0)
local tmp_right2= vec(0,0,0,0,0,0,0,0)
local tmp_vtx=    vec(0,0,0,0,0,0,0,0) 

-- interpolate across scanlines:
--                   ? x1  y x2  y u1 v1 u2 v2
local tmp_span1=  vec(1, 0, 0, 0, 0, 0, 0, 0, 0)
local tmp_span2=  vec(2, 0, 0, 0, 0, 0, 0, 0, 0)
local tmp_delta1= vec(0, 0, 1, 0, 1, 0, 0, 0, 0)
local tmp_delta2= vec(0, 0, 1, 0, 1, 0, 0, 0, 0)

-- "vtx" is a table with vertices {x,y,u,v} starting at 1

function mechkoi_draw_polygon(poly, startidx, vtxcount)
    local vtxcount8 = vtxcount << 3
    local idx = startidx / (8 * 4)
    local min_y = poly:get(1, idx)
    local max_y = min_y
    local miny_idx = 0
    -- Find min_y, max_y, and miny_idx in a single loop
    for n = 8, vtxcount8 - 1, 8 do
        local y = poly:get(n + 1, idx)
        if y < min_y then
            min_y, miny_idx = y, n
        elseif y > max_y then
            max_y = y
        end
    end
    if min_y >= 270 then return end
    if max_y <= 0 then return end
    if max_y > 270 then max_y = 270 end

    -- Round to next integer y (ceil)
    min_y = math.ceil(min_y)
    max_y = math.ceil(max_y)

    local left_idx, right_idx = miny_idx, miny_idx
    local left_height, right_height = 0, 0
    local left_vtx1, left_vtx2 = tmp_left1, tmp_left2
    local right_vtx1, right_vtx2 = tmp_right1, tmp_right2

    right_vtx2:copy(poly, true, startidx + right_idx, 0, 8)
    left_vtx2:copy(poly, true, startidx + left_idx, 0, 8)

    local span1, delta1, tmp, _tline3d = tmp_span1, tmp_delta1, tmp_vtx, tline3d
    local span2, delta2 = tmp_span2, tmp_delta2
    span1[2], span1[3], span1[4] = min_y, 0, min_y
    span2[2], span2[3], span2[4] = min_y, 0, min_y

    while min_y < max_y do
        -- Right edge
        while right_height <= 0 do
            right_vtx2, right_vtx1 = right_vtx1, right_vtx2
            right_idx = (right_idx + vtxcount8 - 8) % vtxcount8
            right_vtx2:copy(poly, true, startidx + right_idx, 0, 8)
            right_vtx2:sub(right_vtx1, tmp)
            right_height = tmp[7]
            tmp:div(tmp.y, true)
            delta1[3], delta1[7], delta1[8] = tmp[0], tmp[3], tmp[4]
            delta2[3], delta2[7], delta2[8] = tmp[0], tmp[5], tmp[6]
            tmp:mul((-right_vtx1.y) % 1.0, true)
            tmp:add(right_vtx1, true)
            span1[3], span1[7], span1[8] = tmp[0],tmp[3], tmp[4]
            span2[3], span2[7], span2[8] = tmp[0],tmp[5], tmp[6]
        end

        -- Left edge
        while left_height <= 0 do
            left_vtx2, left_vtx1 = left_vtx1, left_vtx2
            left_idx = (left_idx + 8) % vtxcount8
            left_vtx2:copy(poly, true, startidx + left_idx, 0, 8)
            left_vtx2:sub(left_vtx1, tmp)
            left_height = tmp[7]
            tmp:div(tmp.y, true)
            delta1[1], delta1[5], delta1[6] = tmp[0], tmp[3], tmp[4]
            delta2[1], delta2[5], delta2[6] = tmp[0], tmp[5], tmp[6]
            tmp:mul((-left_vtx1.y) % 1.0, true)
            tmp:add(left_vtx1, true)
            span1[1], span1[5], span1[6] = tmp[0],tmp[3], tmp[4]
            span2[1], span2[5], span2[6] = tmp[0],tmp[5], tmp[6]
        end

        local cnt = math.min(left_height, right_height)
        for _ = 1, cnt do
            _tline3d(span1)
            _tline3d(span2)
            span1:add(delta1, true)
            span2:add(delta2, true)
        end
        right_height = right_height - cnt
        left_height = left_height - cnt
        min_y = min_y + cnt
    end
end
