comment {
  Minimal subset of UF's Standard.ufm written from the UF language reference.
  Extend only with entries our corpus actually references.
}

Pixel {
init:
  z = #pixel
loop:
  z = #pixel
bailout:
  true
default:
  title = "Pixel"
  maxiter = 1
}

Mandelbrot {
; z_n+1 = z_n^@power + #pixel, starting from @start.
init:
  z = @start
loop:
  z = z^@power + #pixel
bailout:
  |z| <= @bailout
default:
  title = "Mandelbrot"
  maxiter = 250
  param start
    default = (0, 0)
  endparam
  param power
    default = (2, 0)
  endparam
  param bailout
    default = 4.0
  endparam
}


Julia {
; z_n+1 = z_n^@power + @seed.
init:
  z = #pixel
loop:
  z = z^@power + @seed
bailout:
  |z| <= @bailout
default:
  title = "Julia"
  maxiter = 250
  param seed
    default = (-1.25, 0)
  endparam
  param power
    default = (2, 0)
  endparam
  param bailout
    default = 4.0
  endparam
}


FastMandel {
; UF's `builtin: type=1` fast Mandelbrot path. The hardcoded engine is
; equivalent to power=2 z² + #pixel iteration; we map to that directly.
init:
  z = @start
loop:
  z = z*z + #pixel
bailout:
  |z| <= @bailout
default:
  title = "Mandelbrot (Built-in)"
  maxiter = 250
  param start
    default = (0, 0)
  endparam
  param bailout
    default = 4.0
  endparam
}


FastJulia {
; UF's `builtin: type=2` fast Julia path — power=2 z² + @seed.
init:
  z = #pixel
loop:
  z = z*z + @seed
bailout:
  |z| <= @bailout
default:
  title = "Julia (Built-in)"
  maxiter = 250
  param seed
    default = (-1.25, 0)
  endparam
  param bailout
    default = 4.0
  endparam
}


Newton {
; Direct port of UF's Standard.ucm Newton iteration —
;   z = ((p1 - 1) * z^p1 + r) / (p1 * z^(p1 - 1))
; — bails when consecutive z's converge within @bailout.
init:
  z = #pixel
  complex zold = (0,0)
loop:
  zold = z
  z = ((@p1 - 1) * z^@p1 + @r) / (@p1 * z^(@p1 - 1))
bailout:
  |z - zold| >= @bailout
default:
  title = "Newton"
  maxiter = 100
  param p1
    caption = "Exponent"
    default = (3,0)
  endparam
  param r
    caption = "Root"
    default = (1,0)
  endparam
  param bailout
    caption = "Bailout"
    default = 0.00001
    min = 0
  endparam
}


PhoenixJulia {
; Direct port of UF's Standard.ufm PhoenixJulia. The Phoenix iteration
; (Shigehiro Ushiki) couples z(n) and z(n-1):
;   z(n+1) = z(n)^power1  +  seed * z(n)^power2  +  induct * z(n-1)
init:
  z = #pixel
  complex y = (0,0)
  complex newz = (0,0)
loop:
  newz = z^@power1 + z^@power2 * @seed + @induct * y
  y = z
  z = newz
bailout:
  |z| < @bailout
default:
  title = "Phoenix (Julia)"
  maxiter = 1000
  param seed
    caption = "Julia Seed"
    default = (0.56667,0)
  endparam
  param power1
    caption = "Exponent 1"
    default = (2,0)
  endparam
  param power2
    caption = "Exponent 2"
    default = (0,0)
  endparam
  param induct
    caption = "Distortion"
    default = (-0.5,0)
  endparam
  param bailout
    caption = "Bailout"
    default = 1.0e20
  endparam
}


PhoenixMandel {
; Mandelbrot variant of Phoenix — same recurrence as PhoenixJulia but
; the linear term uses #pixel rather than @seed.
init:
  complex y = (0,0)
  complex newz = (0,0)
  if @start == (0,0)
    z = #pixel
  else
    z = @start
  endif
loop:
  newz = z^@power1 + z^@power2 * #pixel + @induct * y
  y = z
  z = newz
bailout:
  |z| < @bailout
default:
  title = "Phoenix (Mandelbrot)"
  maxiter = 1000
  param start
    caption = "Start Value"
    default = (0,0)
  endparam
  param power1
    caption = "Exponent 1"
    default = (2,0)
  endparam
  param power2
    caption = "Exponent 2"
    default = (0,0)
  endparam
  param induct
    caption = "Distortion"
    default = (0.5,0)
  endparam
  param bailout
    caption = "Bailout"
    default = 1.0e20
  endparam
}


LambdaMandelbrot {
; Direct port of UF's Standard.ufm LambdaMandelbrot. Mandelbrot set
; corresponding to the classical Lambda Julia iteration:
;   z = #pixel * z * (1-z)^(power-1)
init:
  z = @start
loop:
  z = #pixel * z * (1-z)^(@power - 1)
bailout:
  |z| < @bailout
default:
  title = "Lambda (Mandelbrot)"
  maxiter = 250
  param start
    caption = "Start Value"
    default = (0.5,0)
  endparam
  param power
    caption = "Exponent"
    default = (2,0)
  endparam
  param bailout
    caption = "Bailout"
    default = 1.0e20
  endparam
}


LambdaJulia {
; Direct port of UF's Standard.ufm LambdaJulia. Julia partner of
; LambdaMandelbrot — iterates the complex logistic map with a fixed seed:
;   z = seed * z * (1-z)^(power-1)
init:
  z = #pixel
loop:
  z = @seed * z * (1-z)^(@power - 1)
bailout:
  |z| < @bailout
default:
  title = "Lambda (Julia)"
  maxiter = 250
  param seed
    caption = "Julia Seed"
    default = (1,0)
  endparam
  param power
    caption = "Exponent"
    default = (2,0)
  endparam
  param bailout
    caption = "Bailout"
    default = 1.0e20
  endparam
}


SlopeMandel {
; Direct port of UF's Standard.ufm SlopeMandel. Iterates three
; simultaneous Mandelbrot orbits at @offset apart and uses cross-deltas
; of a height value (potential / smallest |z| / distance estimator) to
; estimate a surface normal. The normal is encoded as z = vx + i*vy
; for the Lighting coloring algorithm to consume.
init:
  complex c1 = #pixel
  complex c2 = #pixel + @offset
  complex c3 = #pixel + flip(@offset)
  complex z1 = @start
  complex z2 = @start
  complex z3 = @start
  int done = 2
  float modz = 0.0
  float il2 = 1/log(real(@power))
  float lp = log(log(@bailout))
  float e1 = 0.0
  float e2 = 0.0
  float e3 = 0.0
  float vx = 0.0
  float vy = 0.0
  float vz = 0.0
  float vd = 0.0
  float d1 = 0.0
  float d2 = 0.0
  float d3 = 0.0
  float s1 = 1.0e20
  float s2 = 1.0e20
  float s3 = 1.0e20
  complex g1 = (0,0)
  complex g2 = (0,0)
  complex g3 = (0,0)
  complex o1 = (0,0)
  complex o2 = (0,0)
  complex o3 = (0,0)
loop:
  z1 = z1^@power + c1
  z2 = z2^@power + c2
  z3 = z3^@power + c3
  done = done + 1
  if (@zmode == 1)
    d1 = |z1|
    d2 = |z2|
    d3 = |z3|
    if (d1 < s1)
      s1 = d1
    endif
    if (d2 < s2)
      s2 = d2
    endif
    if (d3 < s3)
      s3 = d3
    endif
  elseif (@zmode == 2)
    d1 = abs(real(z1))
    d2 = abs(real(z2))
    d3 = abs(real(z3))
    if (d1 < s1)
      s1 = d1
    endif
    if (d2 < s2)
      s2 = d2
    endif
    if (d3 < s3)
      s3 = d3
    endif
  elseif (@zmode == 3)
    d1 = abs(imag(z1))
    d2 = abs(imag(z2))
    d3 = abs(imag(z3))
    if (d1 < s1)
      s1 = d1
    endif
    if (d2 < s2)
      s2 = d2
    endif
    if (d3 < s3)
      s3 = d3
    endif
  elseif (@zmode == 4)
    d1 = abs(real(z1)) + abs(imag(z1))
    d2 = abs(real(z2)) + abs(imag(z2))
    d3 = abs(real(z3)) + abs(imag(z3))
    if (d1 < s1)
      s1 = d1
    endif
    if (d2 < s2)
      s2 = d2
    endif
    if (d3 < s3)
      s3 = d3
    endif
  elseif (@zmode == 5)
    d1 = abs(atan2(z1))
    d2 = abs(atan2(z2))
    d3 = abs(atan2(z3))
    if (d1 < s1)
      s1 = d1
    endif
    if (d2 < s2)
      s2 = d2
    endif
    if (d3 < s3)
      s3 = d3
    endif
  elseif (@zmode == 6)
    o1 = g1
    o2 = g2
    o3 = g3
    g1 = @power * z1^(@power - 1) * g1 + 1
    g2 = @power * z2^(@power - 1) * g2 + 1
    g3 = @power * z3^(@power - 1) * g3 + 1
  endif
  modz = |z1|
  if (modz > @bailout || @everyiter || done == #maxit + 2)
    if (@zmode == 0)
      e1 = (done + il2*lp - il2*log(log(cabs(z1)))) * @zscale
      e2 = (done + il2*lp - il2*log(log(cabs(z2)))) * @zscale
      e3 = (done + il2*lp - il2*log(log(cabs(z3)))) * @zscale
    elseif (@zmode >= 1 && @zmode <= 5)
      e1 = s1 * @zscale
      e2 = s2 * @zscale
      e3 = s3 * @zscale
    elseif (@zmode == 6)
      e1 = sqrt(2*log(cabs(z1)) * cabs(z1) / cabs(o1)) * @zscale
      e2 = sqrt(2*log(cabs(z2)) * cabs(z2) / cabs(o2)) * @zscale
      e3 = sqrt(2*log(cabs(z3)) * cabs(z3) / cabs(o3)) * @zscale
    endif
    if (@xfer == 1)
      e1 = log(e1)
      e2 = log(e2)
      e3 = log(e3)
    elseif (@xfer == 2)
      e1 = sqrt(e1)
      e2 = sqrt(e2)
      e3 = sqrt(e3)
    elseif (@xfer == 3)
      e1 = (e1)^(1/3)
      e2 = (e2)^(1/3)
      e3 = (e3)^(1/3)
    elseif (@xfer == 4)
      e1 = exp(e1)
      e2 = exp(e2)
      e3 = exp(e3)
    elseif (@xfer == 5)
      e1 = sqr(e1)
      e2 = sqr(e2)
      e3 = sqr(e3)
    elseif (@xfer == 6)
      e1 = (e1)^3
      e2 = (e2)^3
      e3 = (e3)^3
    elseif (@xfer == 7)
      e1 = sin(e1)
      e2 = sin(e2)
      e3 = sin(e3)
    elseif (@xfer == 8)
      e1 = cos(e1)
      e2 = cos(e2)
      e3 = cos(e3)
    elseif (@xfer == 9)
      e1 = tan(e1)
      e2 = tan(e2)
      e3 = tan(e3)
    endif
    e1 = e1 * @zscale2
    e2 = e2 * @zscale2
    e3 = e3 * @zscale2
    vx = e2 - e1
    vy = e3 - e1
    vz = -@offset
    vd = 1/sqrt(sqr(vx) + sqr(vy) + sqr(vz))
    vx = vx * vd
    vy = vy * vd
    vz = vz * vd
    z = vx + flip(vy)
  else
    z = z1
  endif
  if (modz > @bailout)
    done = 0
  endif
bailout:
  done > 0
default:
  title = "Slope (Mandelbrot)"
  maxiter = 1000
  param start
    caption = "Starting Point"
    default = (0,0)
  endparam
  param power
    caption = "Exponent"
    default = (2,0)
  endparam
  param bailout
    caption = "Bail-out Value"
    default = 1.0e20
  endparam
  param offset
    caption = "Orbit Separation"
    default = 0.00000001
  endparam
  param zmode
    caption = "Height Value"
    default = 0
    enum = "potential" "smallest |z|" "smallest |real(z)|" "smallest |imag(z)|" "smallest summ(z)" "smallest |atan(z)|" "distance estimator"
  endparam
  param xfer
    caption = "Height Transfer"
    default = 0
    enum = "linear" "log" "sqrt" "cuberoot" "exp" "sqr" "cube" "sin" "cos" "tan"
  endparam
  param zscale
    caption = "Height Pre-Scale"
    default = 1.0
  endparam
  param zscale2
    caption = "Height Post-Scale"
    default = 0.005
  endparam
  param everyiter
    caption = "Every Iteration"
    default = false
  endparam
}


SlopeNewton {
; Direct port of UF's Standard.ufm SlopeNewton (Ron Barnett, after
; Damien M. Jones). Three-orbit Newton-step variant of SlopeMandel —
; iterates z = z*(rpwr + rrt*z^npwr) at three offset starting points,
; tracks per-mode height (smallest |z|/real/imag/sum/atan, or
; smoothed-iter via exp(-1/|dz|)), and encodes the surface normal as
; z = vx + i*vy for the Lighting coloring algorithm.
init:
  complex pwr = @p1 - 1.0
  complex npwr = -@p1
  complex rpwr = pwr / @p1
  complex rrt = @p2 / @p1
  float pwrtest = 10^(100 / cabs(@p1))
  float isnear = 0.00001 * cabs(@p2)^cabs(@p1)
  bool btest = false
  complex z1 = #pixel
  complex z2 = #pixel + @offset
  complex z3 = #pixel + flip(@offset)
  complex oldz1 = (0,0)
  complex oldz2 = (0,0)
  complex oldz3 = (0,0)
  complex z11 = (0,0)
  complex z12 = (0,0)
  complex z13 = (0,0)
  int done = 2
  float e1 = 0.0
  float e2 = 0.0
  float e3 = 0.0
  float vx = 0.0
  float vy = 0.0
  float vz = 0.0
  float vd = 0.0
  float d1 = 0.0
  float d2 = 0.0
  float d3 = 0.0
  float s1 = 1.0e20
  float s2 = 1.0e20
  float s3 = 1.0e20
  float iterexp1 = 0.0
  float iterexp2 = 0.0
  float iterexp3 = 0.0
loop:
  oldz1 = z1
  z11 = rrt * z1^npwr
  z1 = z1 * (rpwr + z11)
  btest = (cabs(oldz1 - z1) < isnear)
  oldz2 = z2
  z12 = rrt * z2^npwr
  z2 = z2 * (rpwr + z12)
  oldz3 = z3
  z13 = rrt * z3^npwr
  z3 = z3 * (rpwr + z13)
  if (@zmode == 5)
    iterexp1 = iterexp1 + exp(-1 / cabs(oldz1 - z1))
    iterexp2 = iterexp2 + exp(-1 / cabs(oldz2 - z2))
    iterexp3 = iterexp3 + exp(-1 / cabs(oldz3 - z3))
  endif
  done = done + 1
  if (@zmode == 0)
    d1 = |z1|
    d2 = |z2|
    d3 = |z3|
    if (d1 < s1)
      s1 = d1
    endif
    if (d2 < s2)
      s2 = d2
    endif
    if (d3 < s3)
      s3 = d3
    endif
  elseif (@zmode == 1)
    d1 = abs(real(z1))
    d2 = abs(real(z2))
    d3 = abs(real(z3))
    if (d1 < s1)
      s1 = d1
    endif
    if (d2 < s2)
      s2 = d2
    endif
    if (d3 < s3)
      s3 = d3
    endif
  elseif (@zmode == 2)
    d1 = abs(imag(z1))
    d2 = abs(imag(z2))
    d3 = abs(imag(z3))
    if (d1 < s1)
      s1 = d1
    endif
    if (d2 < s2)
      s2 = d2
    endif
    if (d3 < s3)
      s3 = d3
    endif
  elseif (@zmode == 3)
    d1 = abs(real(z1)) + abs(imag(z1))
    d2 = abs(real(z2)) + abs(imag(z2))
    d3 = abs(real(z3)) + abs(imag(z3))
    if (d1 < s1)
      s1 = d1
    endif
    if (d2 < s2)
      s2 = d2
    endif
    if (d3 < s3)
      s3 = d3
    endif
  elseif (@zmode == 4)
    d1 = abs(atan2(z1))
    d2 = abs(atan2(z2))
    d3 = abs(atan2(z3))
    if (d1 < s1)
      s1 = d1
    endif
    if (d2 < s2)
      s2 = d2
    endif
    if (d3 < s3)
      s3 = d3
    endif
  endif
  if (btest || cabs(z1) > pwrtest || @everyiter || done == #maxit + 2)
    if (@zmode >= 0 && @zmode <= 4)
      e1 = s1 * @zscale
      e2 = s2 * @zscale
      e3 = s3 * @zscale
    elseif (@zmode == 5)
      e1 = iterexp1 * @zscale
      e2 = iterexp2 * @zscale
      e3 = iterexp3 * @zscale
    endif
    if (@xfer == 1)
      e1 = log(e1)
      e2 = log(e2)
      e3 = log(e3)
    elseif (@xfer == 2)
      e1 = sqrt(e1)
      e2 = sqrt(e2)
      e3 = sqrt(e3)
    elseif (@xfer == 3)
      e1 = (e1)^(1/3)
      e2 = (e2)^(1/3)
      e3 = (e3)^(1/3)
    elseif (@xfer == 4)
      e1 = exp(e1)
      e2 = exp(e2)
      e3 = exp(e3)
    elseif (@xfer == 5)
      e1 = sqr(e1)
      e2 = sqr(e2)
      e3 = sqr(e3)
    elseif (@xfer == 6)
      e1 = (e1)^3
      e2 = (e2)^3
      e3 = (e3)^3
    elseif (@xfer == 7)
      e1 = sin(e1)
      e2 = sin(e2)
      e3 = sin(e3)
    elseif (@xfer == 8)
      e1 = cos(e1)
      e2 = cos(e2)
      e3 = cos(e3)
    elseif (@xfer == 9)
      e1 = tan(e1)
      e2 = tan(e2)
      e3 = tan(e3)
    endif
    e1 = e1 * @zscale2
    e2 = e2 * @zscale2
    e3 = e3 * @zscale2
    vx = e2 - e1
    vy = e3 - e1
    vz = -@offset
    vd = 1/sqrt(sqr(vx) + sqr(vy) + sqr(vz))
    vx = vx * vd
    vy = vy * vd
    vz = vz * vd
    z = vx + flip(vy)
  else
    z = z1
  endif
  if (btest || cabs(z1) > pwrtest)
    done = 0
  endif
bailout:
  done > 0
default:
  title = "Slope (Newton)"
  maxiter = 1000
  param p1
    caption = "Exponent"
    default = (3,0)
  endparam
  param p2
    caption = "Root"
    default = (1,0)
  endparam
  param offset
    caption = "Orbit Separation"
    default = 0.00000001
  endparam
  param zmode
    caption = "Height Value"
    default = 5
    enum = "smallest |z|" "smallest |real(z)|" "smallest |imag(z)|" "smallest summ(z)" "smallest |atan(z)|" "smoothed iteration"
  endparam
  param xfer
    caption = "Height Transfer"
    default = 0
    enum = "linear" "log" "sqrt" "cuberoot" "exp" "sqr" "cube" "sin" "cos" "tan"
  endparam
  param zscale
    caption = "Height Pre-Scale"
    default = 1.0
  endparam
  param zscale2
    caption = "Height Post-Scale"
    default = 0.01
  endparam
  param everyiter
    caption = "Every Iteration"
    default = false
  endparam
}


EmbossedMandelbrot {
; Direct port of UF's Standard.ufm EmbossedMandelbrot. Iterates two
; Mandelbrot orbits offset by a small light-direction vector and
; encodes a per-orbit "part" value (iteration count / half-plane
; counter / smallest-|z| iter / log-trunc / angle bin) into z = part1
; + i*part2 for the Emboss coloring algorithm to compare.
init:
  float theta = (90 - @lightangle) * pi / 180.0
  float size = @sizefac * 0.0065 / #magn
  complex dr = size * (cos(theta) + flip(sin(theta)))
  complex c1 = #pixel - dr
  complex c2 = #pixel + dr
  complex z1 = @manparam
  complex z2 = @manparam
  int iter1 = 0
  int iter2 = 0
  int iter = 0
  float r = 0.0
  float t = 0.0
  float rmin = 1.0e20
  float part1 = 0.0
  float part2 = 0.0
loop:
  iter = iter + 1
  if (iter1 == 0)
    z1 = z1^@nexp + c1
    if (|z1| > @bailout)
      iter1 = iter
    endif
    if (@parttype == 1)
      if (real(z1) > 0.0)
        part1 = part1 + 1.0
      endif
    elseif (@parttype == 2)
      if (imag(z1) > 0.0)
        part1 = part1 + 1.0
      endif
    elseif (@parttype == 3)
      r = |z1|
      if (r < rmin)
        rmin = r
        part1 = iter
      endif
    elseif (@parttype == 4)
      part1 = real(trunc(log(z1)))
    elseif (@parttype == 5)
      t = 0.5 * atan2(z1) / pi
      if (t < 0.0)
        t = t + 1.0
      endif
      t = t * @numsect
      part1 = real(trunc(t))
    else
      part1 = iter1
    endif
  endif
  if (iter2 == 0)
    z2 = z2^@nexp + c2
    if (|z2| > @bailout)
      iter2 = iter
    endif
    if (@parttype == 1)
      if (real(z2) > 0.0)
        part2 = part2 + 1.0
      endif
    elseif (@parttype == 2)
      if (imag(z2) > 0.0)
        part2 = part2 + 1.0
      endif
    elseif (@parttype == 3)
      r = |z2|
      if (r < rmin)
        rmin = r
        part2 = iter
      endif
    elseif (@parttype == 4)
      part2 = real(trunc(log(z2)))
    elseif (@parttype == 5)
      t = 0.5 * atan2(z2) / pi
      if (t < 0.0)
        t = t + 1.0
      endif
      t = t * @numsect
      part2 = real(trunc(t))
    else
      part2 = iter2
    endif
  endif
  z = part1 + flip(part2)
bailout:
  (iter1 == 0) || (iter2 == 0)
default:
  title = "Embossed (Mandelbrot)"
  maxiter = 100
  param manparam
    caption = "Starting Point"
    default = (0,0)
  endparam
  param nexp
    caption = "Exponent"
    default = 2.0
  endparam
  param bailout
    caption = "Bail-out Value"
    default = 4.0
  endparam
  param parttype
    caption = "Emboss Type"
    default = 0
    enum = "Iteration" "Real(z) > 0" "Imag(z) > 0" "Smallest Magnitude" "Magnitude" "Angle"
  endparam
  param numsect
    caption = "Number of Sections"
    default = 2
  endparam
  param lightangle
    caption = "Light Angle"
    default = 0.0
  endparam
  param sizefac
    caption = "Contour Size"
    default = 1.0
  endparam
}
