import benchy, chroma, pixie, pixie/internal, strformat
import benchy, chroma, pixie

proc newRoundedRectImage1(w, h, r: int, color: Color): Image =
  result = newImage(w, h)
  let ctx = newContext(result)
  ctx.fillStyle = color(0, 1, 0, 1)
  let
    pos = vec2(0, 0)
    wh = vec2(w.float32, h.float32)
    r = r.float32
  ctx.fillRoundedRect(rect(pos, wh), r)

proc newRoundedRectImage15(w, h, r: int, color: Color): Image =
  let path = newPath()
  let
    pos = vec2(0, 0)
    wh = vec2(w.float32, h.float32)
    r = r.float32
  path.roundedRect(rect(pos, wh), r, r, r, r)
  result = path.fillImage(w, h, color(0, 1, 0, 1))

proc newRoundedRectImage2(w, h, r: int, color: Color): Image =
  result = newImage(w, h)
  result.fill(color)

  let
    w1 = w - 1
    h1 = h - 1
  for y in 0 ..< r:
    for x in 0 ..< r:
      var a: float32 = 0
      for s in 0 ..< 5:
        let
          yc = y.float32 + s.float32 / 5 + (1 / 5 / 2)
          xc = r.float32 - sqrt(r.float32*r.float32 - (yc - r.float32) ^ 2)
        let mid = (x.float32 - xc + 1).clamp(0, 1)
        a += 1/5 * mid

      if a < 1:
        var c = color
        c.a = a
        let cx = c.rgbx
        result.setRgbaUnsafe(x, y, cx)
        result.setRgbaUnsafe(w1 - x, y, cx)
        result.setRgbaUnsafe(w1 - x, h1 - y, cx)
        result.setRgbaUnsafe(x, h1 - y, cx)

proc newRoundedRectImage3(w, h, r: int, color: Color): Image =
  result = newImage(w, h)
  result.fill(color)

  if r == 0:
    return

  const
    q = 5
    qf = q.float32
    qoffset: float32 = (1 / qf / 2)

  let
    r = r.clamp(0, min(w, h) div 2)
    rf = r.float32
    w1 = w - 1
    h1 = h - 1
    rgbx = color.rgbx
    channels = [rgbx.r.uint32, rgbx.g.uint32, rgbx.b.uint32, rgbx.a.uint32]

  var coverage = newSeq[uint8](r)

  for y in 0 ..< r:
    zeroMem(coverage[0].addr, coverage.len)
    var yf: float32 = y.float32 + qoffset
    for m in 0 ..< q:
      let hit = sqrt(rf^2 - yf^2)
      coverage[hit.int] += max((1 - (hit - hit.trunc)) * 255 / qf, 0).uint8
      for x in hit.int + 1 ..< r:
        coverage[x] += (255 div q).uint8
      yf += 1 / qf

    for x in 0 ..< r:
      let coverage = 255 - coverage[x]
      if coverage != 255:
        var cx: ColorRGBX
        cx.r = ((channels[0] * coverage) div 255).uint8
        cx.g = ((channels[1] * coverage) div 255).uint8
        cx.b = ((channels[2] * coverage) div 255).uint8
        cx.a = ((channels[3] * coverage) div 255).uint8

        let
          xn = r - x - 1
          yn = r - y - 1
        result.setRgbaUnsafe(xn, yn, cx)
        result.setRgbaUnsafe(w1 - xn, yn, cx)
        result.setRgbaUnsafe(w1 - xn, h1 - yn, cx)
        result.setRgbaUnsafe(xn, h1 - yn, cx)

const r = 16

let img1 = newRoundedRectImage1(200, 200, r, color(0, 1, 0, 1))
img1.writeFile("rrect_current.png")
let img2 = newRoundedRectImage3(200, 200, r, color(0, 1, 0, 1))
img2.writeFile("rrect_new.png")

let (diffScore, diffImage) = diff(img1, img2)
echo &"score: {diffScore}"
diffImage.writeFile("rrect_diff.png")

timeIt "fill rounded rect via path 1":
  for i in 0 ..< 10:
    discard newRoundedRectImage1(200, 200, r, color(0, 1, 0, 1))

timeIt "fill rounded rect via path 1.5":
  for i in 0 ..< 10:
    discard newRoundedRectImage15(200, 200, r, color(0, 1, 0, 1))

timeIt "fill rounded rect via math 2":
  for i in 0 ..< 10:
    discard newRoundedRectImage2(200, 200, 50, color(0, 1, 0, 1))

timeIt "fill rounded rect via math 3":
  for i in 0 ..< 10:
    discard newRoundedRectImage3(200, 200, r, color(0, 1, 0, 1))