Patch title: Release 93 bulk changes
Abstract:
File: /graphic/misc/dither.pli
Key:
    Removed line
    Added line
   
module "/pliant/language/unsafe.pli"
module "/pliant/language/stream.pli"
module "/pliant/util/crypto/random.pli"

constant dither_matrix_mini 192
constant dither_matrix_maxi 384
constant dither_matrix_release 1


type DitherMatrix
  field (Array Array:Int) coefs
  field Int size_x size_y

method m resize size_x size_y
  arg_rw DitherMatrix m ; arg Int size_x size_y
  m size_x := size_x ; m size_y := size_y
  m:coefs size := size_y
  for (var Int y) 0 size_y-1
    m:coefs:y size := size_x

method m '' x y -> coef
  arg DitherMatrix m ; arg Int x y ; arg_C Int coef
  check x>=0 and x<m:size_x
  check y>=0 and y<m:size_y
  coef :> m:coefs:y x

method m cell xx yy -> coef
  arg DitherMatrix m ; arg Int xx yy ; arg_C Int coef
  var Int x := xx%m:size_x
  if x<0
    x += m size_x
  var Int y := yy%m:size_y
  if y<0
    y += m size_y
  coef :> m:coefs:y x

method m save filename
  arg_rw DitherMatrix m ; arg Str filename
  (var Stream s) open filename out+mkdir+safe
  s writeline "Pliant dithering matrix"
  s writeline "release "+string:dither_matrix_release
  s writeline "size_x "+(string m:size_x)
  s writeline "size_y "+(string m:size_y)
  s writeline ""
  for (var Int y) 0 m:size_y-1
    s raw_write addressof:(m 0 y) m:size_x*Int:size

method m load filename -> status
  arg_rw DitherMatrix m ; arg Str filename ; arg Status status
  (var Stream s) open filename in+safe
  var Int r := undefined ; var Int sx sy
  while { var Str l := s readline ; l<>"" }
    l parse word:"release" r
    l parse word:"size_x" sx
    l parse word:"size_y" sy
  if r<>dither_matrix_release
    return failure
  m resize sx sy
  for (var Int y) 0 m:size_y-1
    s raw_read addressof:(m 0 y) m:size_x*Int:size
  status := shunt s=success success failure

function random n -> r
  arg Int n r
  memory_strong_random addressof:(var uInt u) uInt:size
  # memory_random addressof:(var uInt u) uInt:size
  r := u%(cast n uInt)

function distance m x y radius x_stretch y_stretch -> d
  arg DitherMatrix m ; arg Int x y radius x_stretch y_stretch ; arg Float d
  var Int radius2 := radius*radius
  d := 0
  for (var Int yy) y-radius y+radius
    var Int dy2 := (yy-y)*(yy-y)*y_stretch*y_stretch
    if dy2<=radius2
      for (var Int xx) x-radius x+radius
        var Int d2 := (xx-x)*(xx-x)*x_stretch*x_stretch+dy2
        if d2<=radius2
          if (m cell xx yy)=defined
            d += 1/d2

function random_matrix sx sy try radius x_stretch y_stretch -> m
  arg Int sx sy try radius x_stretch y_stretch ; arg DitherMatrix m
  m resize sx sy
  var Int count := sx*sy
  (var Array:Int buffer_x) size := count
  (var Array:Int buffer_y) size := count
  for (var Int y) 0 sy-1
    for (var Int x) 0 sx-1
      m x y := undefined
      buffer_x x+y*sx := x
      buffer_y x+y*sx := y
  for (var Int index) 1 sx*sy
    part point "point "+string:index+"/"+(string sx*sy)
      var Int selected ; var Float best := undefined
      for (var Int lap) 1 (min (count+1)\2 try)
        var Int i := random count
        var Float d := distance m buffer_x:i buffer_y:i radius x_stretch y_stretch
        if best=undefined or d<best
          selected := i ; best := d
      m buffer_x:selected buffer_y:selected := index
      count -= 1
      buffer_x selected := buffer_x count
      buffer_y selected := buffer_y count


function is_prime n -> p
  arg Int n ; arg CBool p
  if n<2
    return false
  var Int i := 2
  while i*i<=n
    if n%i=0
      return false
    i += 1
  p := true


function dither_matrix index options -> m
  arg Int index ; arg Str options ; arg DitherMatrix m
  var Int dpi_x := options option "dpi_x" Int 1
  var Int dpi_y := options option "dpi_y" Int 1
  if (m load "file:/pliant_data/pliant/graphic/dithering/matrix"+string:index+(shunt dpi_x>dpi_y "x" "")+(shunt dpi_y>dpi_x "y" "")+".bin")=failure
    var Int m1 := options option "dither_matrix_mini" Int dither_matrix_mini
    var Int m2 := options option "dither_matrix_maxi" Int dither_matrix_maxi
    part shake "select dithering pattern size for channel "+string:index
      part shake_x
        var Int sx := m1+(random m2-m1+1)
        if not is_prime:sx
          restart shake_x
      part shake_y
        var Int sy := m1+(random m2-m1+1)
        if not is_prime:sy
          restart shake_y
      for (var Int j) 0 index-1
        (var DitherMatrix mm) load "file:/pliant_data/pliant/graphic/dithering/matrix"+string:j+(shunt dpi_x>dpi_y "x" "")+(shunt dpi_y>dpi_x "y" "")+".bin"
        if mm:size_x=sx or mm:size_y=sy
          restart shake
    part matrix "compute "+string:sx+" x "+string:sy+" dither matrix for channel "+string:index
      m := random_matrix sx sy 64 16 (shunt dpi_y>dpi_x 2 1) (shunt dpi_x>dpi_y 2 1)
    m save "file:/pliant_data/pliant/graphic/dithering/matrix"+string:index+(shunt dpi_x>dpi_y "x" "")+(shunt dpi_y>dpi_x "y" "")+".bin"


export DitherMatrix '. size_x' '. size_y' '' '. cell'
export dither_matrix