https://github.com/akkartik/mu/blob/main/apps/hest-life.mu
   1 # Conway's Game of Life in a Hestified way
   2 #   https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
   3 #   https://ivanish.ca/hest-podcast
   4 #
   5 # To build:
   6 #   $ ./translate apps/hest-life.mu
   7 # I run it on my 2.5GHz Linux laptop like this:
   8 #   $ qemu-system-i386 code.img
   9 #
  10 # If things seem too fast or too slow on your computer, adjust the loop bounds
  11 # in the function `linger` at the bottom. Its value will depend on how you
  12 # accelerate Qemu (`-accel help`). Mu will eventually get a clock to obviate
  13 # the need for this tuning.
  14 #
  15 # Keyboard shortcuts:
  16 #   space: pause/resume
  17 #   0: restart time
  18 #   l: start looping from 0 to curren time
  19 #   L: stop looping
  20 #   +: zoom in
  21 #   -: zoom out
  22 
  23 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
  24   var env-storage: environment
  25   var env/esi: (addr environment) <- address env-storage
  26   initialize-environment env
  27   var second-buffer: screen
  28   var second-screen/edi: (addr screen) <- address second-buffer
  29   initialize-screen second-screen, 0x80, 0x30, 1/include-pixels
  30   render second-screen, env
  31   convert-graphemes-to-pixels second-screen
  32   copy-pixels second-screen, screen
  33   {
  34     edit keyboard, env
  35     var play?/eax: (addr boolean) <- get env, play?
  36     compare *play?, 0/false
  37     {
  38       break-if-=
  39       step env
  40       clear-screen second-screen
  41       render second-screen, env
  42       convert-graphemes-to-pixels second-screen
  43       copy-pixels second-screen, screen
  44     }
  45     linger env
  46     loop
  47   }
  48 }
  49 
  50 type environment {
  51   data: (handle array handle array cell)
  52   zoom: int  # 0 = 1024 px per cell; 5 = 4px per cell; each step adjusts by a factor of 4
  53   tick: int
  54   play?: boolean
  55   loop: int  # if non-zero, return tick to 0 after this point
  56 }
  57 
  58 type cell {
  59   curr: boolean
  60   next: boolean
  61 }
  62 
  63 fn render screen: (addr screen), _self: (addr environment) {
  64   var self/esi: (addr environment) <- copy _self
  65   var zoom/eax: (addr int) <- get self, zoom
  66   compare *zoom, 0
  67   {
  68     break-if-!=
  69     clear-screen screen
  70     render0 screen, self
  71   }
  72   compare *zoom, 1
  73   {
  74     break-if-!=
  75     clear-screen screen
  76     render1 screen, self
  77   }
  78   compare *zoom, 4
  79   {
  80     break-if-!=
  81     render4 screen, self
  82   }
  83   # clock
  84   var tick-a/eax: (addr int) <- get self, tick
  85   set-cursor-position screen, 0x78/x, 0/y
  86   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, *tick-a, 7/fg 0/bg
  87 }
  88 
  89 # Lots of hardcoded constants for now.
  90 # TODO: split this up into a primitive to render a single cell and its
  91 # incoming edges (but not the neighboring nodes they emanate from)
  92 fn render0 screen: (addr screen), _self: (addr environment) {
  93   var self/esi: (addr environment) <- copy _self
  94   # cell border
  95   draw-vertical-line   screen,  0xc0/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
  96   draw-vertical-line   screen, 0x340/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
  97   draw-horizontal-line screen,  0x40/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
  98   draw-horizontal-line screen, 0x2c0/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
  99   # neighboring inputs, corners
 100   var color/eax: int <- state-color self, 0x7f/cur-topleftx, 0x5f/cur-toplefty
 101   draw-rect screen,  0x90/xmin   0x10/ymin,    0xb0/xmax   0x30/ymax,  color
 102   color <- state-color self, 0x81/cur-toprightx, 0x5f/cur-toprighty
 103   draw-rect screen, 0x350/xmin   0x10/ymin,   0x370/xmax   0x30/ymax,  color
 104   color <- state-color self, 0x7f/cur-botleftx, 0x61/cur-botlefty
 105   draw-rect screen,  0x90/xmin  0x2d0/ymin,    0xb0/xmax  0x2f0/ymax,  color
 106   color <- state-color self, 0x81/cur-botrightx, 0x61/cur-botrighty
 107   draw-rect screen, 0x350/xmin  0x2d0/ymin,   0x370/xmax  0x2f0/ymax,  color
 108   # neighboring inputs, edges
 109   color <- state-color self, 0x80/cur-topx, 0x5f/cur-topy
 110   draw-rect screen, 0x1f0/xmin   0x10/ymin,   0x210/xmax   0x30/ymax,  color
 111   color <- state-color self, 0x7f/cur-leftx, 0x60/cur-lefty
 112   draw-rect screen,  0x90/xmin  0x170/ymin,    0xb0/xmax  0x190/ymax,  color
 113   color <- state-color self, 0x80/cur-botx, 0x61/cur-boty
 114   draw-rect screen, 0x1f0/xmin  0x2d0/ymin,   0x210/xmax  0x2f0/ymax,  color
 115   color <- state-color self, 0x81/cur-rightx, 0x60/cur-righty
 116   draw-rect screen, 0x350/xmin  0x170/ymin,   0x370/xmax  0x190/ymax,  color
 117   # sum node
 118   draw-rect screen, 0x170/xsmin 0x140/ysmin,  0x190/xsmax 0x160/ysmax, 0x40/color
 119   set-cursor-position screen, 0x2d/scol, 0x13/srow
 120   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "+", 0xf/color, 0/bg
 121   # conveyors from neighboring inputs to sum node
 122   draw-monotonic-bezier screen,  0xa0/x0  0x20/y0,  0x100/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
 123   draw-monotonic-bezier screen,  0xa0/x0 0x180/y0,   0xc0/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
 124   draw-monotonic-bezier screen,  0xa0/x0 0x2e0/y0,  0x100/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
 125   draw-monotonic-bezier screen, 0x200/x0  0x20/y0,  0x180/x1  0x90/y1,  0x180/xs 0x150/ys,  4/color
 126   draw-monotonic-bezier screen, 0x200/x0 0x2e0/y0,  0x180/x1 0x200/y1,  0x180/xs 0x150/ys,  4/color
 127   draw-monotonic-bezier screen, 0x360/x0  0x20/y0,  0x180/x1  0xc0/y1,  0x180/xs 0x150/ys,  4/color
 128   draw-monotonic-bezier screen, 0x360/x0 0x180/y0,  0x35c/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
 129   draw-monotonic-bezier screen, 0x360/x0 0x2e0/y0,  0x180/x1 0x200/y1,  0x180/xs 0x150/ys,  4/color
 130   # filter node
 131   draw-rect screen, 0x200/xfmin 0x1c0/yfmin, 0x220/xfmax 0x1e0/yfmax, 0x31/color
 132   set-cursor-position screen, 0x40/fcol, 0x1b/frow
 133   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "?", 0xf/color, 0/bg
 134   # conveyor from sum node to filter node
 135   draw-line screen 0x180/xs, 0x150/ys, 0x210/xf, 0x1d0/yf, 0xa2/color
 136   # cell outputs at corners
 137   var color/eax: int <- state-color self, 0x80/curx, 0x60/cury
 138   draw-rect screen,  0xd0/xmin  0x50/ymin,  0xf0/xmax  0x70/ymax, color
 139   draw-rect screen, 0x310/xmin  0x50/ymin, 0x330/xmax  0x70/ymax, color
 140   draw-rect screen,  0xd0/xmin 0x290/ymin,  0xf0/xmax 0x2b0/ymax, color
 141   draw-rect screen, 0x310/xmin 0x290/ymin, 0x330/xmax 0x2b0/ymax, color
 142   # cell outputs at edges
 143   draw-rect screen, 0x1f0/xmin  0x50/ymin, 0x210/xmax  0x70/ymax, color
 144   draw-rect screen,  0xd0/xmin 0x170/ymin,  0xf0/xmax 0x190/ymax, color
 145   draw-rect screen, 0x1f0/xmin 0x290/ymin, 0x210/xmax 0x2b0/ymax, color
 146   draw-rect screen, 0x310/xmin 0x170/ymin, 0x330/xmax 0x190/ymax, color
 147   # conveyors from filter to outputs
 148   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x1c0/x1  0x60/y1,  0xe0/x2   0x60/y2,  0x2a/color
 149   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,   0xe0/x1 0x1c0/y1,  0xe0/x2  0x180/y2,  0x2a/color
 150   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x1c0/x1 0x2a0/y1,  0xe0/x2  0x2a0/y2,  0x2a/color
 151   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x210/x1  0x60/y1, 0x200/x2   0x60/y2,  0x2a/color
 152   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x210/x1 0x230/y1, 0x200/x2  0x2a0/y2,  0x2a/color
 153   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x320/x1 0x120/y1, 0x320/x2   0x60/y2,  0x2a/color
 154   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x320/x1 0x1c0/y1  0x320/x2  0x180/y2,  0x2a/color
 155   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x320/x1 0x230/y1, 0x320/x2  0x2a0/y2,  0x2a/color
 156   # time-variant portion: 16 repeating steps
 157   var tick-a/eax: (addr int) <- get self, tick
 158   var progress/eax: int <- copy *tick-a
 159   progress <- and 0xf
 160   # 7 time steps for getting inputs to sum
 161   {
 162     compare progress, 7
 163     break-if->=
 164     var u/xmm7: float <- convert progress
 165     var six/eax: int <- copy 6
 166     var six-f/xmm0: float <- convert six
 167     u <- divide six-f
 168     # points on conveyors from neighboring cells
 169     draw-bezier-point screen, u,  0xa0/x0  0x20/y0, 0x100/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
 170     draw-bezier-point screen, u,  0xa0/x0 0x180/y0,  0xc0/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
 171     draw-bezier-point screen, u,  0xa0/x0 0x2e0/y0, 0x100/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
 172     draw-bezier-point screen, u, 0x200/x0  0x20/y0, 0x180/x1  0x90/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
 173     draw-bezier-point screen, u, 0x200/x0 0x2e0/y0, 0x180/x1 0x200/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
 174     draw-bezier-point screen, u, 0x360/x0  0x20/y0, 0x180/x1  0xc0/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
 175     draw-bezier-point screen, u, 0x360/x0 0x180/y0, 0x35c/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
 176     draw-bezier-point screen, u, 0x360/x0 0x2e0/y0, 0x180/x1 0x200/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
 177     return
 178   }
 179   # two time steps for getting count to filter
 180   progress <- subtract 7
 181   {
 182     compare progress, 2
 183     break-if->=
 184     progress <- increment  # (0, 1) => (1, 2)
 185     var u/xmm7: float <- convert progress
 186     var three/eax: int <- copy 3
 187     var three-f/xmm0: float <- convert three
 188     u <- divide three-f
 189     draw-linear-point screen, u, 0x180/xs, 0x150/ys, 0x210/xf, 0x1d0/yf, 7/color, 4/radius
 190     set-cursor-position screen, 0x3a/scol, 0x18/srow
 191     var n/eax: int <- num-live-neighbors self, 0x80/curx, 0x60/cury
 192     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
 193     return
 194   }
 195   # final 7 time steps for updating output
 196   progress <- subtract 2
 197   # points on conveyors to outputs
 198   var u/xmm7: float <- convert progress
 199   var six/eax: int <- copy 6
 200   var six-f/xmm0: float <- convert six
 201   u <- divide six-f
 202   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x1c0/x1  0x60/y1,  0xe0/x2   0x60/y2, 7/color, 4/radius
 203   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,   0xe0/x1 0x1c0/y1,  0xe0/x2  0x180/y2, 7/color, 4/radius
 204   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x1c0/x1 0x2a0/y1,  0xe0/x2  0x2a0/y2, 7/color, 4/radius
 205   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x210/xf  0x60/y1, 0x200/x2   0x60/y2, 7/color, 4/radius
 206   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x210/xf 0x230/y1, 0x200/x2  0x2a0/y2, 7/color, 4/radius
 207   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x320/x1 0x120/y1, 0x320/x2   0x60/y2, 7/color, 4/radius
 208   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x320/x1 0x1c0/y1, 0x320/x2  0x180/y2, 7/color, 4/radius
 209   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x320/x1 0x230/y1, 0x320/x2  0x2a0/y2, 7/color, 4/radius
 210 }
 211 
 212 fn render1 screen: (addr screen), _self: (addr environment) {
 213   var self/esi: (addr environment) <- copy _self
 214   # cell borders
 215   draw-vertical-line   screen,  0xe0/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
 216   draw-vertical-line   screen, 0x200/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
 217   draw-vertical-line   screen, 0x320/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
 218   draw-horizontal-line screen,  0x60/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
 219   draw-horizontal-line screen, 0x180/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
 220   draw-horizontal-line screen, 0x2a0/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
 221   # cell 0: outputs
 222   var color/eax: int <- state-color self, 0x80/curx, 0x60/cury
 223   draw-rect screen,  0xe8/xmin  0x68/ymin, 0x118/xmax   0x98/ymax, color
 224   draw-rect screen,  0xe8/xmin  0xd0/ymin, 0x118/xmax  0x100/ymax, color
 225   draw-rect screen,  0xe8/xmin 0x148/ymin, 0x118/xmax  0x178/ymax, color
 226   draw-rect screen, 0x158/xmin  0x68/ymin, 0x188/xmax   0x98/ymax, color
 227   draw-rect screen, 0x158/xmin 0x148/ymin, 0x188/xmax  0x178/ymax, color
 228   draw-rect screen, 0x1c8/xmin  0x68/ymin, 0x1f8/xmax   0x98/ymax, color
 229   draw-rect screen, 0x1c8/xmin  0xd0/ymin, 0x1f8/xmax  0x100/ymax, color
 230   draw-rect screen, 0x1c8/xmin 0x148/ymin, 0x1f8/xmax  0x178/ymax, color
 231   # cell 1: outputs
 232   var color/eax: int <- state-color self, 0x81/curx, 0x60/cury
 233   draw-rect screen, 0x208/xmin  0x68/ymin, 0x238/xmax   0x98/ymax, color
 234   draw-rect screen, 0x208/xmin  0xd0/ymin, 0x238/xmax  0x100/ymax, color
 235   draw-rect screen, 0x208/xmin 0x148/ymin, 0x238/xmax  0x178/ymax, color
 236   draw-rect screen, 0x278/xmin  0x68/ymin, 0x2a8/xmax   0x98/ymax, color
 237   draw-rect screen, 0x278/xmin 0x148/ymin, 0x2a8/xmax  0x178/ymax, color
 238   draw-rect screen, 0x2e8/xmin  0x68/ymin, 0x318/xmax   0x98/ymax, color
 239   draw-rect screen, 0x2e8/xmin  0xd0/ymin, 0x318/xmax  0x100/ymax, color
 240   draw-rect screen, 0x2e8/xmin 0x148/ymin, 0x318/xmax  0x178/ymax, color
 241   # cell 2: outputs
 242   var color/eax: int <- state-color self, 0x80/curx, 0x61/cury
 243   draw-rect screen,  0xe8/xmin 0x188/ymin, 0x118/xmax  0x1b8/ymax, color
 244   draw-rect screen,  0xe8/xmin 0x1f0/ymin, 0x118/xmax  0x220/ymax, color
 245   draw-rect screen,  0xe8/xmin 0x268/ymin, 0x118/xmax  0x298/ymax, color
 246   draw-rect screen, 0x158/xmin 0x188/ymin, 0x188/xmax  0x1b8/ymax, color
 247   draw-rect screen, 0x158/xmin 0x268/ymin, 0x188/xmax  0x298/ymax, color
 248   draw-rect screen, 0x1c8/xmin 0x188/ymin, 0x1f8/xmax  0x1b8/ymax, color
 249   draw-rect screen, 0x1c8/xmin 0x1f0/ymin, 0x1f8/xmax  0x220/ymax, color
 250   draw-rect screen, 0x1c8/xmin 0x268/ymin, 0x1f8/xmax  0x298/ymax, color
 251   # cell 3: outputs
 252   var color/eax: int <- state-color self, 0x81/curx, 0x61/cury
 253   draw-rect screen, 0x208/xmin 0x188/ymin, 0x238/xmax  0x1b8/ymax, color
 254   draw-rect screen, 0x208/xmin 0x1f0/ymin, 0x238/xmax  0x220/ymax, color
 255   draw-rect screen, 0x208/xmin 0x268/ymin, 0x238/xmax  0x298/ymax, color
 256   draw-rect screen, 0x278/xmin 0x188/ymin, 0x2a8/xmax  0x1b8/ymax, color
 257   draw-rect screen, 0x278/xmin 0x268/ymin, 0x2a8/xmax  0x298/ymax, color
 258   draw-rect screen, 0x2e8/xmin 0x188/ymin, 0x318/xmax  0x1b8/ymax, color
 259   draw-rect screen, 0x2e8/xmin 0x1f0/ymin, 0x318/xmax  0x220/ymax, color
 260   draw-rect screen, 0x2e8/xmin 0x268/ymin, 0x318/xmax  0x298/ymax, color
 261   # neighboring nodes
 262   var color/eax: int <- state-color self, 0x7f/curx, 0x5f/cury
 263   draw-rect screen,  0xa8/xmin  0x28/ymin,  0xd8/xmax   0x58/ymax, color
 264   var color/eax: int <- state-color self, 0x80/curx, 0x5f/cury
 265   draw-rect screen, 0x158/xmin  0x28/ymin, 0x188/xmax   0x58/ymax, color
 266   draw-rect screen, 0x1c8/xmin  0x28/ymin, 0x1f8/xmax   0x58/ymax, color
 267   var color/eax: int <- state-color self, 0x81/curx, 0x5f/cury
 268   draw-rect screen, 0x208/xmin  0x28/ymin, 0x238/xmax   0x58/ymax, color
 269   draw-rect screen, 0x278/xmin  0x28/ymin, 0x2a8/xmax   0x58/ymax, color
 270   var color/eax: int <- state-color self, 0x82/curx, 0x5f/cury
 271   draw-rect screen, 0x328/xmin  0x28/ymin, 0x358/xmax   0x58/ymax, color
 272   var color/eax: int <- state-color self, 0x7f/curx, 0x60/cury
 273   draw-rect screen,  0xa8/xmin  0xd0/ymin,  0xd8/xmax  0x100/ymax, color
 274   draw-rect screen,  0xa8/xmin 0x148/ymin,  0xd8/xmax  0x178/ymax, color
 275   var color/eax: int <- state-color self, 0x82/curx, 0x60/cury
 276   draw-rect screen, 0x328/xmin  0xd0/ymin, 0x358/xmax  0x100/ymax, color
 277   draw-rect screen, 0x328/xmin 0x148/ymin, 0x358/xmax  0x178/ymax, color
 278   var color/eax: int <- state-color self, 0x7f/curx, 0x61/cury
 279   draw-rect screen,  0xa8/xmin 0x188/ymin,  0xd8/xmax  0x1b8/ymax, color
 280   draw-rect screen,  0xa8/xmin 0x1f0/ymin,  0xd8/xmax  0x220/ymax, color
 281   var color/eax: int <- state-color self, 0x82/curx, 0x61/cury
 282   draw-rect screen, 0x328/xmin 0x188/ymin, 0x358/xmax  0x1b8/ymax, color
 283   draw-rect screen, 0x328/xmin 0x1f0/ymin, 0x358/xmax  0x220/ymax, color
 284   var color/eax: int <- state-color self, 0x7f/curx, 0x62/cury
 285   draw-rect screen,  0xa8/xmin 0x2a8/ymin,  0xd8/xmax  0x2d8/ymax, color
 286   var color/eax: int <- state-color self, 0x80/curx, 0x62/cury
 287   draw-rect screen, 0x158/xmin 0x2a8/ymin, 0x188/xmax  0x2d8/ymax, color
 288   draw-rect screen, 0x1c8/xmin 0x2a8/ymin, 0x1f8/xmax  0x2d8/ymax, color
 289   var color/eax: int <- state-color self, 0x81/curx, 0x62/cury
 290   draw-rect screen, 0x208/xmin 0x2a8/ymin, 0x238/xmax  0x2d8/ymax, color
 291   draw-rect screen, 0x278/xmin 0x2a8/ymin, 0x2a8/xmax  0x2d8/ymax, color
 292   var color/eax: int <- state-color self, 0x82/curx, 0x62/cury
 293   draw-rect screen, 0x328/xmin 0x2a8/ymin, 0x358/xmax  0x2d8/ymax, color
 294   # cell 0: sum and filter nodes
 295   draw-rect screen, 0x148/xsmin  0xc8/ysmin, 0x158/xsmax  0xd8/ysmax, 0x40/color
 296   draw-rect screen, 0x180/xfmin  0xf8/yfmin, 0x190/xfmax 0x108/yfmax, 0x31/color
 297   # cell 1: sum and filter nodes
 298   draw-rect screen, 0x268/xsmin  0xc8/ysmin, 0x278/xsmax  0xd8/ysmax, 0x40/color
 299   draw-rect screen, 0x2a0/xfmin  0xf8/yfmin, 0x2b0/xfmax 0x108/yfmax, 0x31/color
 300   # cell 2: sum and filter nodes
 301   draw-rect screen, 0x148/xsmin 0x1e8/ysmin, 0x158/xsmax 0x1f8/ysmax, 0x40/color
 302   draw-rect screen, 0x180/xfmin 0x218/yfmin, 0x190/xfmax 0x228/yfmax, 0x31/color
 303   # cell 3: sum and filter nodes
 304   draw-rect screen, 0x268/xsmin 0x1e8/ysmin, 0x278/xsmax 0x1f8/ysmax, 0x40/color
 305   draw-rect screen, 0x2a0/xfmin 0x218/yfmin, 0x2b0/xfmax 0x228/yfmax, 0x31/color
 306   # neighbor counts
 307   var n/eax: int <- num-live-neighbors self, 0x80/curx, 0x60/cury
 308   set-cursor-position screen, 0x2d, 0xe
 309   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
 310   var n/eax: int <- num-live-neighbors self, 0x81/curx, 0x60/cury
 311   set-cursor-position screen, 0x52, 0xe
 312   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
 313   var n/eax: int <- num-live-neighbors self, 0x80/curx, 0x61/cury
 314   set-cursor-position screen, 0x2d, 0x20
 315   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
 316   var n/eax: int <- num-live-neighbors self, 0x81/curx, 0x61/cury
 317   set-cursor-position screen, 0x52, 0x20
 318   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
 319   # cell 0: conveyors from neighboring inputs to sum node
 320   draw-monotonic-bezier screen,  0xc0/x0  0x40/y0,  0x100/x1  0xd0/ys, 0x150/xs  0xd0/ys,  4/color
 321   draw-monotonic-bezier screen,  0xc0/x0  0xe8/y0,   0xc0/x1  0xd0/ys, 0x150/xs  0xd0/ys,  4/color
 322   draw-monotonic-bezier screen,  0xc0/x0 0x1a0/y0,   0xe0/x1  0xd0/ys, 0x150/xs  0xd0/ys,  4/color
 323   draw-monotonic-bezier screen, 0x170/x0  0x40/y0,  0x150/x1  0x80/y1, 0x150/xs  0xd0/ys,  4/color
 324   draw-monotonic-bezier screen, 0x170/x0 0x1a0/y0,  0x150/x1 0x1a0/y1, 0x150/xs  0xd0/ys,  4/color
 325   draw-monotonic-bezier screen, 0x220/x0  0x40/y0,  0x150/x1  0x80/y1, 0x150/xs  0xd0/ys,  4/color
 326   draw-monotonic-bezier screen, 0x220/x0  0xe8/y0,  0x220/x1  0xd0/y1, 0x150/xs  0xd0/ys,  4/color
 327   draw-monotonic-bezier screen, 0x220/x0 0x1a0/y0,  0x180/x1 0x1a0/y1, 0x150/xs  0xd0/ys,  4/color
 328   # cell 0: conveyors from filter to outputs
 329   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x160/x1  0x8c/y1, 0x100/x2  0x80/y2,  0x2a/color
 330   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2  0xe8/y2,  0x2a/color
 331   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2 0x160/y2,  0x2a/color
 332   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x188/x1  0x80/y1, 0x170/x2  0x80/y2,  0x2a/color
 333   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x188/x1 0x160/y1, 0x170/x2 0x160/y2,  0x2a/color
 334   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2  0x80/y2,  0x2a/color
 335   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1  0x1e0/x2  0xe8/y2,  0x2a/color
 336   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2 0x160/y2,  0x2a/color
 337   # cell 0: time-variant portion: 16 repeating steps
 338   $render1:cell0: {
 339     var tick-a/eax: (addr int) <- get self, tick
 340     var progress/eax: int <- copy *tick-a
 341     progress <- and 0xf
 342     # cell 0: 7 time steps for getting inputs to sum
 343     {
 344       compare progress, 7
 345       break-if->=
 346       var u/xmm7: float <- convert progress
 347       var six/eax: int <- copy 6
 348       var six-f/xmm0: float <- convert six
 349       u <- divide six-f
 350       # points on conveyors from neighboring cells
 351       draw-bezier-point screen, u,  0xc0/x0  0x40/y0, 0x100/x1  0xd0/ys, 0x150/xs  0xd0/ys, 7/color, 4/radius
 352       draw-bezier-point screen, u,  0xc0/x0  0xe8/y0,  0xc0/x1  0xd0/ys, 0x150/xs  0xd0/ys, 7/color, 4/radius
 353       draw-bezier-point screen, u,  0xc0/x0 0x1a0/y0,  0xe0/x1  0xd0/ys, 0x150/xs  0xd0/ys, 7/color, 4/radius
 354       draw-bezier-point screen, u, 0x170/x0  0x40/y0, 0x150/x1  0x80/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
 355       draw-bezier-point screen, u, 0x170/x0 0x1a0/y0, 0x150/x1 0x1a0/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
 356       draw-bezier-point screen, u, 0x220/x0  0x40/y0, 0x150/x1  0x80/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
 357       draw-bezier-point screen, u, 0x220/x0  0xe8/y0, 0x220/x1  0xd0/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
 358       draw-bezier-point screen, u, 0x220/x0 0x1a0/y0, 0x180/x1 0x1a0/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
 359       break $render1:cell0
 360     }
 361     # cell 0: two time steps for getting count to filter
 362     progress <- subtract 7
 363     {
 364       compare progress, 2
 365       break-if->=
 366       break $render1:cell0
 367     }
 368     # cell 0: final 7 time steps for updating output
 369     progress <- subtract 2
 370     # cell 0: points on conveyors to outputs
 371     var u/xmm7: float <- convert progress
 372     var six/eax: int <- copy 6
 373     var six-f/xmm0: float <- convert six
 374     u <- divide six-f
 375     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x160/x1  0x8c/y1, 0x100/x2  0x80/y2, 7/color, 4/radius
 376     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2  0xe8/y2, 7/color, 4/radius
 377     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2 0x160/y2, 7/color, 4/radius
 378     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x188/xf  0x80/y1, 0x170/x2  0x80/y2, 7/color, 4/radius
 379     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x188/xf 0x160/y1, 0x170/x2 0x160/y2, 7/color, 4/radius
 380     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2  0x80/y2, 7/color, 4/radius
 381     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2  0xe8/y2, 7/color, 4/radius
 382     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2 0x160/y2, 7/color, 4/radius
 383   }
 384   # cell 1: conveyors from neighboring inputs to sum node
 385   draw-monotonic-bezier screen, 0x1e0/x0  0x40/y0,  0x220/x1  0xd0/ys, 0x270/xs  0xd0/ys,  4/color
 386   draw-monotonic-bezier screen, 0x1e0/x0  0xe8/y0,  0x1e0/x1  0xd0/ys, 0x270/xs  0xd0/ys,  4/color
 387   draw-monotonic-bezier screen, 0x1e0/x0 0x1a0/y0,  0x200/x1  0xd0/ys, 0x270/xs  0xd0/ys,  4/color
 388   draw-monotonic-bezier screen, 0x290/x0  0x40/y0,  0x270/x1  0x80/y1, 0x270/xs  0xd0/ys,  4/color
 389   draw-monotonic-bezier screen, 0x290/x0 0x1a0/y0,  0x270/x1 0x1a0/y1, 0x270/xs  0xd0/ys,  4/color
 390   draw-monotonic-bezier screen, 0x340/x0  0x40/y0,  0x270/x1  0x80/y1, 0x270/xs  0xd0/ys,  4/color
 391   draw-monotonic-bezier screen, 0x340/x0  0xe8/y0,  0x340/x1  0xd0/y1, 0x270/xs  0xd0/ys,  4/color
 392   draw-monotonic-bezier screen, 0x340/x0 0x1a0/y0,  0x2a0/x1 0x1a0/y1, 0x270/xs  0xd0/ys,  4/color
 393   # cell 1: conveyors from filter to outputs
 394   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x280/x1  0x8c/y1, 0x220/x2  0x80/y2,  0x2a/color
 395   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2  0xe8/y2,  0x2a/color
 396   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2 0x160/y2,  0x2a/color
 397   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x2a8/x1  0x80/y1, 0x290/x2  0x80/y2,  0x2a/color
 398   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x2a8/x1 0x160/y1, 0x290/x2 0x160/y2,  0x2a/color
 399   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2  0x80/y2,  0x2a/color
 400   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1  0x300/x2  0xe8/y2,  0x2a/color
 401   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2 0x160/y2,  0x2a/color
 402   # cell 1: time-variant portion: 16 repeating steps
 403   $render1:cell1: {
 404     var tick-a/eax: (addr int) <- get self, tick
 405     var progress/eax: int <- copy *tick-a
 406     progress <- and 0xf
 407     # cell 1: 7 time steps for getting inputs to sum
 408     {
 409       compare progress, 7
 410       break-if->=
 411       var u/xmm7: float <- convert progress
 412       var six/eax: int <- copy 6
 413       var six-f/xmm0: float <- convert six
 414       u <- divide six-f
 415       # points on conveyors from neighboring cells
 416       draw-bezier-point screen, u, 0x1e0/x0  0x40/y0, 0x220/x1  0xd0/ys, 0x270/xs  0xd0/ys, 7/color, 4/radius
 417       draw-bezier-point screen, u, 0x1e0/x0  0xe8/y0, 0x1e0/x1  0xd0/ys, 0x270/xs  0xd0/ys, 7/color, 4/radius
 418       draw-bezier-point screen, u, 0x1e0/x0 0x1a0/y0, 0x200/x1  0xd0/ys, 0x270/xs  0xd0/ys, 7/color, 4/radius
 419       draw-bezier-point screen, u, 0x290/x0  0x40/y0, 0x270/x1  0x80/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
 420       draw-bezier-point screen, u, 0x290/x0 0x1a0/y0, 0x270/x1 0x1a0/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
 421       draw-bezier-point screen, u, 0x340/x0  0x40/y0, 0x270/x1  0x80/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
 422       draw-bezier-point screen, u, 0x340/x0  0xe8/y0, 0x340/x1  0xd0/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
 423       draw-bezier-point screen, u, 0x340/x0 0x1a0/y0, 0x2a0/x1 0x1a0/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
 424       break $render1:cell1
 425     }
 426     # cell 1: two time steps for getting count to filter
 427     progress <- subtract 7
 428     {
 429       compare progress, 2
 430       break-if->=
 431       break $render1:cell1
 432     }
 433     # cell 1: final 7 time steps for updating output
 434     progress <- subtract 2
 435     # cell 1: points on conveyors to outputs
 436     var u/xmm7: float <- convert progress
 437     var six/eax: int <- copy 6
 438     var six-f/xmm0: float <- convert six
 439     u <- divide six-f
 440     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x280/x1  0x8c/y1, 0x220/x2  0x80/y2, 7/color, 4/radius
 441     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2  0xe8/y2, 7/color, 4/radius
 442     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2 0x160/y2, 7/color, 4/radius
 443     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x2a8/xf  0x80/y1, 0x290/x2  0x80/y2, 7/color, 4/radius
 444     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x2a8/xf 0x160/y1, 0x290/x2 0x160/y2, 7/color, 4/radius
 445     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2  0x80/y2, 7/color, 4/radius
 446     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2  0xe8/y2, 7/color, 4/radius
 447     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2 0x160/y2, 7/color, 4/radius
 448   }
 449   # cell 2: conveyors from neighboring inputs to sum node
 450   draw-monotonic-bezier screen,  0xc0/x0 0x160/y0,  0x100/x1 0x1f0/ys, 0x150/xs 0x1f0/ys,  4/color
 451   draw-monotonic-bezier screen,  0xc0/x0 0x208/y0,   0xc0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys,  4/color
 452   draw-monotonic-bezier screen,  0xc0/x0 0x2c0/y0,   0xe0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys,  4/color
 453   draw-monotonic-bezier screen, 0x170/x0 0x160/y0,  0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys,  4/color
 454   draw-monotonic-bezier screen, 0x170/x0 0x2c0/y0,  0x150/x1 0x2c0/y1, 0x150/xs 0x1f0/ys,  4/color
 455   draw-monotonic-bezier screen, 0x220/x0 0x160/y0,  0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys,  4/color
 456   draw-monotonic-bezier screen, 0x220/x0 0x208/y0,  0x220/x1 0x1f0/y1, 0x150/xs 0x1f0/ys,  4/color
 457   draw-monotonic-bezier screen, 0x220/x0 0x2c0/y0,  0x180/x1 0x2c0/y1, 0x150/xs 0x1f0/ys,  4/color
 458   # cell 2: conveyors from filter to outputs
 459   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x160/x1 0x1ac/y1, 0x100/x2 0x1a0/y2,  0x2a/color
 460   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x208/y2,  0x2a/color
 461   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x280/y2,  0x2a/color
 462   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x188/x1 0x1a0/y1, 0x170/x2 0x1a0/y2,  0x2a/color
 463   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x188/x1 0x280/y1, 0x170/x2 0x280/y2,  0x2a/color
 464   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x1a0/y2,  0x2a/color
 465   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1  0x1e0/x2 0x208/y2,  0x2a/color
 466   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x280/y2,  0x2a/color
 467   # cell 2: time-variant portion: 16 repeating steps
 468   $render1:cell2: {
 469     var tick-a/eax: (addr int) <- get self, tick
 470     var progress/eax: int <- copy *tick-a
 471     progress <- and 0xf
 472     # cell 2: 7 time steps for getting inputs to sum
 473     {
 474       compare progress, 7
 475       break-if->=
 476       var u/xmm7: float <- convert progress
 477       var six/eax: int <- copy 6
 478       var six-f/xmm0: float <- convert six
 479       u <- divide six-f
 480       # points on conveyors from neighboring cells
 481       draw-bezier-point screen, u,  0xc0/x0 0x160/y0, 0x100/x1 0x1f0/ys, 0x150/xs 0x1f0/ys, 7/color, 4/radius
 482       draw-bezier-point screen, u,  0xc0/x0 0x208/y0,  0xc0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys, 7/color, 4/radius
 483       draw-bezier-point screen, u,  0xc0/x0 0x2c0/y0,  0xe0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys, 7/color, 4/radius
 484       draw-bezier-point screen, u, 0x170/x0 0x160/y0, 0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
 485       draw-bezier-point screen, u, 0x170/x0 0x2c0/y0, 0x150/x1 0x2c0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
 486       draw-bezier-point screen, u, 0x220/x0 0x160/y0, 0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
 487       draw-bezier-point screen, u, 0x220/x0 0x208/y0, 0x220/x1 0x1f0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
 488       draw-bezier-point screen, u, 0x220/x0 0x2c0/y0, 0x180/x1 0x2c0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
 489       break $render1:cell2
 490     }
 491     # cell 2: two time steps for getting count to filter
 492     progress <- subtract 7
 493     {
 494       compare progress, 2
 495       break-if->=
 496       break $render1:cell2
 497     }
 498     # cell 2: final 7 time steps for updating output
 499     progress <- subtract 2
 500     # cell 2: points on conveyors to outputs
 501     var u/xmm7: float <- convert progress
 502     var six/eax: int <- copy 6
 503     var six-f/xmm0: float <- convert six
 504     u <- divide six-f
 505     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x160/x1 0x1ac/y1, 0x100/x2 0x1a0/y2, 7/color, 4/radius
 506     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x208/y2, 7/color, 4/radius
 507     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x280/y2, 7/color, 4/radius
 508     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x188/xf 0x1a0/y1, 0x170/x2 0x1a0/y2, 7/color, 4/radius
 509     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x188/xf 0x280/y1, 0x170/x2 0x280/y2, 7/color, 4/radius
 510     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x1a0/y2, 7/color, 4/radius
 511     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x208/y2, 7/color, 4/radius
 512     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x280/y2, 7/color, 4/radius
 513   }
 514   # cell 3: conveyors from neighboring inputs to sum node
 515   draw-monotonic-bezier screen, 0x1e0/x0 0x160/y0,  0x220/x1 0x1f0/ys, 0x270/xs 0x1f0/ys,  4/color
 516   draw-monotonic-bezier screen, 0x1e0/x0 0x208/y0,  0x1e0/x1 0x1f0/ys, 0x270/xs 0x1f0/ys,  4/color
 517   draw-monotonic-bezier screen, 0x1e0/x0 0x2c0/y0,  0x200/x1 0x1f0/ys, 0x270/xs 0x1f0/ys,  4/color
 518   draw-monotonic-bezier screen, 0x290/x0 0x160/y0,  0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys,  4/color
 519   draw-monotonic-bezier screen, 0x290/x0 0x2c0/y0,  0x270/x1 0x2c0/y1, 0x270/xs 0x1f0/ys,  4/color
 520   draw-monotonic-bezier screen, 0x340/x0 0x160/y0,  0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys,  4/color
 521   draw-monotonic-bezier screen, 0x340/x0 0x208/y0,  0x340/x1 0x1f0/y1, 0x270/xs 0x1f0/ys,  4/color
 522   draw-monotonic-bezier screen, 0x340/x0 0x2c0/y0,  0x2a0/x1 0x2c0/y1, 0x270/xs 0x1f0/ys,  4/color
 523   # cell 3: conveyors from filter to outputs
 524   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x280/x1 0x1ac/y1, 0x220/x2 0x1a0/y2,  0x2a/color
 525   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x208/y2,  0x2a/color
 526   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x280/y2,  0x2a/color
 527   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x2a8/x1 0x1a0/y1, 0x290/x2 0x1a0/y2,  0x2a/color
 528   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x2a8/x1 0x280/y1, 0x290/x2 0x280/y2,  0x2a/color
 529   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x1a0/y2,  0x2a/color
 530   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1  0x300/x2 0x208/y2,  0x2a/color
 531   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x280/y2,  0x2a/color
 532   # cell 3: time-variant portion: 16 repeating steps
 533   $render1:cell3: {
 534     var tick-a/eax: (addr int) <- get self, tick
 535     var progress/eax: int <- copy *tick-a
 536     progress <- and 0xf
 537     # cell 3: 7 time steps for getting inputs to sum
 538     {
 539       compare progress, 7
 540       break-if->=
 541       var u/xmm7: float <- convert progress
 542       var six/eax: int <- copy 6
 543       var six-f/xmm0: float <- convert six
 544       u <- divide six-f
 545       # points on conveyors from neighboring cells
 546       draw-bezier-point screen, u, 0x1e0/x0 0x160/y0, 0x220/x1 0x1f0/ys, 0x270/xs 0x1f0/ys, 7/color, 4/radius
 547       draw-bezier-point screen, u, 0x1e0/x0 0x208/y0, 0x1e0/x1 0x1f0/ys, 0x270/xs 0x1f0/ys, 7/color, 4/radius
 548       draw-bezier-point screen, u, 0x1e0/x0 0x2c0/y0, 0x200/x1 0x1f0/ys, 0x270/xs 0x1f0/ys, 7/color, 4/radius
 549       draw-bezier-point screen, u, 0x290/x0 0x160/y0, 0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
 550       draw-bezier-point screen, u, 0x290/x0 0x2c0/y0, 0x270/x1 0x2c0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
 551       draw-bezier-point screen, u, 0x340/x0 0x160/y0, 0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
 552       draw-bezier-point screen, u, 0x340/x0 0x208/y0, 0x340/x1 0x1f0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
 553       draw-bezier-point screen, u, 0x340/x0 0x2c0/y0, 0x2a0/x1 0x2c0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
 554       break $render1:cell3
 555     }
 556     # cell 3: two time steps for getting count to filter
 557     progress <- subtract 7
 558     {
 559       compare progress, 2
 560       break-if->=
 561       break $render1:cell3
 562     }
 563     # cell 3: final 7 time steps for updating output
 564     progress <- subtract 2
 565     # cell 3: points on conveyors to outputs
 566     var u/xmm7: float <- convert progress
 567     var six/eax: int <- copy 6
 568     var six-f/xmm0: float <- convert six
 569     u <- divide six-f
 570     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x280/x1 0x1ac/y1, 0x220/x2 0x1a0/y2, 7/color, 4/radius
 571     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x208/y2, 7/color, 4/radius
 572     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x280/y2, 7/color, 4/radius
 573     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x2a8/xf 0x1a0/y1, 0x290/x2 0x1a0/y2, 7/color, 4/radius
 574     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x2a8/xf 0x280/y1, 0x290/x2 0x280/y2, 7/color, 4/radius
 575     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x1a0/y2, 7/color, 4/radius
 576     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x208/y2, 7/color, 4/radius
 577     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x280/y2, 7/color, 4/radius
 578   }
 579 }
 580 
 581 fn draw-bezier-point screen: (addr screen), u: float, x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, color: int, radius: int {
 582   var _cy/eax: int <- bezier-point u, y0, y1, y2
 583   var cy/ecx: int <- copy _cy
 584   var cx/eax: int <- bezier-point u, x0, x1, x2
 585   draw-disc screen, cx, cy, radius, color, 0xf/border-color=white
 586 }
 587 
 588 fn draw-linear-point screen: (addr screen), u: float, x0: int, y0: int, x1: int, y1: int, color: int, radius: int {
 589   var _cy/eax: int <- line-point u, y0, y1
 590   var cy/ecx: int <- copy _cy
 591   var cx/eax: int <- line-point u, x0, x1
 592   draw-disc screen, cx, cy, radius, color, 0xf/border-color=white
 593 }
 594 
 595 fn edit keyboard: (addr keyboard), _self: (addr environment) {
 596   var self/esi: (addr environment) <- copy _self
 597   var key/eax: byte <- read-key keyboard
 598   # space: play/pause
 599   {
 600     compare key, 0x20/space
 601     break-if-!=
 602     var play?/eax: (addr boolean) <- get self, play?
 603     compare *play?, 0/false
 604     {
 605       break-if-=
 606       copy-to *play?, 0/false
 607       return
 608     }
 609     copy-to *play?, 1/true
 610     return
 611   }
 612   # 0: back to start
 613   {
 614     compare key, 0x30/0
 615     break-if-!=
 616     clear-environment self
 617     return
 618   }
 619   # l: loop from here to start
 620   {
 621     compare key, 0x6c/l
 622     break-if-!=
 623     var tick-a/eax: (addr int) <- get self, tick
 624     var tick/eax: int <- copy *tick-a
 625     var loop/ecx: (addr int) <- get self, loop
 626     copy-to *loop, tick
 627     return
 628   }
 629   # L: reset loop
 630   {
 631     compare key, 0x4c/L
 632     break-if-!=
 633     var loop/eax: (addr int) <- get self, loop
 634     copy-to *loop, 0
 635     return
 636   }
 637   # -: zoom out
 638   {
 639     compare key, 0x2d/-
 640     break-if-!=
 641     var zoom/eax: (addr int) <- get self, zoom
 642     compare *zoom, 1
 643     {
 644       break-if-!=
 645       copy-to *zoom, 4
 646     }
 647     compare *zoom, 0
 648     {
 649       break-if-!=
 650       copy-to *zoom, 1
 651     }
 652     # set tick to a multiple of zoom
 653     var tick-a/edx: (addr int) <- get self, tick
 654     clear-lowest-bits tick-a, *zoom
 655     return
 656   }
 657   # +: zoom in
 658   {
 659     compare key, 0x2b/+
 660     break-if-!=
 661     var zoom/eax: (addr int) <- get self, zoom
 662     compare *zoom, 1
 663     {
 664       break-if-!=
 665       copy-to *zoom, 0
 666     }
 667     compare *zoom, 4
 668     {
 669       break-if-!=
 670       copy-to *zoom, 1
 671     }
 672     # set tick to a multiple of zoom
 673     var tick-a/edx: (addr int) <- get self, tick
 674     clear-lowest-bits tick-a, *zoom
 675     return
 676   }
 677 }
 678 
 679 fn step _self: (addr environment) {
 680   var self/esi: (addr environment) <- copy _self
 681   var tick-a/ecx: (addr int) <- get self, tick
 682   var zoom/edx: (addr int) <- get self, zoom
 683   compare *zoom, 0
 684   {
 685     break-if-!=
 686     increment *tick-a
 687   }
 688   compare *zoom, 1
 689   {
 690     break-if-!=
 691     # I wanted to speed up time, but that doesn't seem very usable.
 692 #?     add-to *tick-a, 2
 693     increment *tick-a
 694   }
 695   compare *zoom, 4
 696   {
 697     break-if-!=
 698     add-to *tick-a, 0x10
 699   }
 700   var tick/eax: int <- copy *tick-a
 701   tick <- and 0xf
 702   compare tick, 0
 703   {
 704     break-if-!=
 705     step4 self
 706   }
 707   var loop-a/eax: (addr int) <- get self, loop
 708   compare *loop-a, 0
 709   {
 710     break-if-=
 711     var loop/eax: int <- copy *loop-a
 712     compare *tick-a, loop
 713     break-if-<
 714     clear-environment self
 715   }
 716 }
 717 
 718 fn initialize-environment _self: (addr environment) {
 719   var self/esi: (addr environment) <- copy _self
 720   var zoom/eax: (addr int) <- get self, zoom
 721   copy-to *zoom, 0
 722   var play?/eax: (addr boolean) <- get self, play?
 723   copy-to *play?, 1/true
 724   var data-ah/eax: (addr handle array handle array cell) <- get self, data
 725   populate data-ah, 0x100
 726   var data/eax: (addr array handle array cell) <- lookup *data-ah
 727   var y/ecx: int <- copy 0
 728   {
 729     compare y, 0xc0
 730     break-if->=
 731     var dest-ah/eax: (addr handle array cell) <- index data, y
 732     populate dest-ah, 0x100
 733     y <- increment
 734     loop
 735   }
 736   set self, 0x80, 0x5f, 1/alive
 737   set self, 0x81, 0x5f, 1/alive
 738   set self, 0x7f, 0x60, 1/alive
 739   set self, 0x80, 0x60, 1/alive
 740   set self, 0x80, 0x61, 1/alive
 741   flush self
 742 }
 743 
 744 fn clear-environment _self: (addr environment) {
 745   var self/esi: (addr environment) <- copy _self
 746   var tick/eax: (addr int) <- get self, tick
 747   copy-to *tick, 0
 748   # don't touch zoom or play settings
 749   var data-ah/eax: (addr handle array handle array cell) <- get self, data
 750   var data/eax: (addr array handle array cell) <- lookup *data-ah
 751   var y/ecx: int <- copy 0
 752   {
 753     compare y, 0xc0
 754     break-if->=
 755     var row-ah/eax: (addr handle array cell) <- index data, y
 756     var row/eax: (addr array cell) <- lookup *row-ah
 757     var x/edx: int <- copy 0
 758     {
 759       compare x, 0x100
 760       break-if->=
 761       var dest/eax: (addr cell) <- index row, x
 762       clear-object dest
 763       x <- increment
 764       loop
 765     }
 766     y <- increment
 767     loop
 768   }
 769   set self, 0x80, 0x5f, 1/alive
 770   set self, 0x81, 0x5f, 1/alive
 771   set self, 0x7f, 0x60, 1/alive
 772   set self, 0x80, 0x60, 1/alive
 773   set self, 0x80, 0x61, 1/alive
 774   flush self
 775 }
 776 
 777 fn set _self: (addr environment), _x: int, _y: int, _val: boolean {
 778   var self/esi: (addr environment) <- copy _self
 779   var data-ah/eax: (addr handle array handle array cell) <- get self, data
 780   var data/eax: (addr array handle array cell) <- lookup *data-ah
 781   var y/ecx: int <- copy _y
 782   var row-ah/eax: (addr handle array cell) <- index data, y
 783   var row/eax: (addr array cell) <- lookup *row-ah
 784   var x/ecx: int <- copy _x
 785   var cell/eax: (addr cell) <- index row, x
 786   var dest/eax: (addr boolean) <- get cell, next
 787   var val/ecx: boolean <- copy _val
 788   copy-to *dest, val
 789 }
 790 
 791 fn state _self: (addr environment), _x: int, _y: int -> _/eax: boolean {
 792   var self/esi: (addr environment) <- copy _self
 793   var x/ecx: int <- copy _x
 794   var y/edx: int <- copy _y
 795   # clip at the edge
 796   compare x, 0
 797   {
 798     break-if->=
 799     return 0/false
 800   }
 801   compare y, 0
 802   {
 803     break-if->=
 804     return 0/false
 805   }
 806   compare x, 0x100/width
 807   {
 808     break-if-<
 809     return 0/false
 810   }
 811   compare y, 0xc0/height
 812   {
 813     break-if-<
 814     return 0/false
 815   }
 816   var data-ah/eax: (addr handle array handle array cell) <- get self, data
 817   var data/eax: (addr array handle array cell) <- lookup *data-ah
 818   var row-ah/eax: (addr handle array cell) <- index data, y
 819   var row/eax: (addr array cell) <- lookup *row-ah
 820   var cell/eax: (addr cell) <- index row, x
 821   var src/eax: (addr boolean) <- get cell, curr
 822   return *src
 823 }
 824 
 825 fn state-color _self: (addr environment), x: int, y: int -> _/eax: int {
 826   var self/esi: (addr environment) <- copy _self
 827   var color/ecx: int <- copy 0x1a/dead
 828   {
 829     var state/eax: boolean <- state self, x, y
 830     compare state, 0/dead
 831     break-if-=
 832     color <- copy 0xf/alive
 833   }
 834   return color
 835 }
 836 
 837 fn flush  _self: (addr environment) {
 838   var self/esi: (addr environment) <- copy _self
 839   var data-ah/eax: (addr handle array handle array cell) <- get self, data
 840   var _data/eax: (addr array handle array cell) <- lookup *data-ah
 841   var data/esi: (addr array handle array cell) <- copy _data
 842   var y/ecx: int <- copy 0
 843   {
 844     compare y, 0xc0/height
 845     break-if->=
 846     var row-ah/eax: (addr handle array cell) <- index data, y
 847     var _row/eax: (addr array cell) <- lookup *row-ah
 848     var row/ebx: (addr array cell) <- copy _row
 849     var x/edx: int <- copy 0
 850     {
 851       compare x, 0x100/width
 852       break-if->=
 853       var cell-a/eax: (addr cell) <- index row, x
 854       var curr-a/edi: (addr boolean) <- get cell-a, curr
 855       var next-a/esi: (addr boolean) <- get cell-a, next
 856       var val/eax: boolean <- copy *next-a
 857       copy-to *curr-a, val
 858       copy-to *next-a, 0/dead
 859       x <- increment
 860       loop
 861     }
 862     y <- increment
 863     loop
 864   }
 865 }
 866 
 867 fn render4 screen: (addr screen), _self: (addr environment) {
 868   var self/esi: (addr environment) <- copy _self
 869   var y/ecx: int <- copy 0
 870   {
 871     compare y, 0xc0/height
 872     break-if->=
 873     var x/edx: int <- copy 0
 874     {
 875       compare x, 0x100/width
 876       break-if->=
 877       var state/eax: boolean <- state self, x, y
 878       compare state, 0/false
 879       {
 880         break-if-=
 881         render4-cell screen, x, y, 0xf/alive
 882       }
 883       compare state, 0/false
 884       {
 885         break-if-!=
 886         render4-cell screen, x, y, 0x1a/dead
 887       }
 888       x <- increment
 889       loop
 890     }
 891     y <- increment
 892     loop
 893   }
 894 }
 895 
 896 fn render4-cell screen: (addr screen), x: int, y: int, color: int {
 897   var xmin/eax: int <- copy x
 898   xmin <- shift-left 2
 899   var xmax/ecx: int <- copy xmin
 900   xmax <- add 4
 901   var ymin/edx: int <- copy y
 902   ymin <- shift-left 2
 903   var ymax/ebx: int <- copy ymin
 904   ymax <- add 4
 905   draw-rect screen, xmin ymin, xmax ymax, color
 906 }
 907 
 908 fn step4 _self: (addr environment) {
 909   var self/esi: (addr environment) <- copy _self
 910   var y/ecx: int <- copy 0
 911   {
 912     compare y, 0xc0/height
 913     break-if->=
 914     var x/edx: int <- copy 0
 915     {
 916       compare x, 0x100/width
 917       break-if->=
 918       var n/eax: int <- num-live-neighbors self, x, y
 919       # if neighbors < 2, die of loneliness
 920       {
 921         compare n, 2
 922         break-if->=
 923         set self, x, y, 0/dead
 924       }
 925       # if neighbors > 3, die of overcrowding
 926       {
 927         compare n, 3
 928         break-if-<=
 929         set self, x, y, 0/dead
 930       }
 931       # if neighbors = 2, preserve state
 932       {
 933         compare n, 2
 934         break-if-!=
 935         var old-state/eax: boolean <- state self, x, y
 936         set self, x, y, old-state
 937       }
 938       # if neighbors = 3, cell quickens to life
 939       {
 940         compare n, 3
 941         break-if-!=
 942         set self, x, y, 1/live
 943       }
 944       x <- increment
 945       loop
 946     }
 947     y <- increment
 948     loop
 949   }
 950   flush self
 951 }
 952 
 953 fn num-live-neighbors _self: (addr environment), x: int, y: int -> _/eax: int {
 954   var self/esi: (addr environment) <- copy _self
 955   var result/edi: int <- copy 0
 956   # row above: zig
 957   decrement y
 958   decrement x
 959   var s/eax: boolean <- state self, x, y
 960   {
 961     compare s, 0/false
 962     break-if-=
 963     result <- increment
 964   }
 965   increment x
 966   s <- state self, x, y
 967   {
 968     compare s, 0/false
 969     break-if-=
 970     result <- increment
 971   }
 972   increment x
 973   s <- state self, x, y
 974   {
 975     compare s, 0/false
 976     break-if-=
 977     result <- increment
 978   }
 979   # curr row: zag
 980   increment y
 981   s <- state self, x, y
 982   {
 983     compare s, 0/false
 984     break-if-=
 985     result <- increment
 986   }
 987   subtract-from x, 2
 988   s <- state self, x, y
 989   {
 990     compare s, 0/false
 991     break-if-=
 992     result <- increment
 993   }
 994   # row below: zig
 995   increment y
 996   s <- state self, x, y
 997   {
 998     compare s, 0/false
 999     break-if-=
1000     result <- increment
1001   }
1002   increment x
1003   s <- state self, x, y
1004   {
1005     compare s, 0/false
1006     break-if-=
1007     result <- increment
1008   }
1009   increment x
1010   s <- state self, x, y
1011   {
1012     compare s, 0/false
1013     break-if-=
1014     result <- increment
1015   }
1016   return result
1017 }
1018 
1019 fn linger _self: (addr environment) {
1020   var self/esi: (addr environment) <- copy _self
1021   var i/ecx: int <- copy 0
1022   {
1023     compare i, 0x10000000  # Kartik's Linux with -enable-kvm
1024 #?     compare i, 0x8000000  # Kartik's Mac with -accel tcg
1025     break-if->=
1026     i <- increment
1027     loop
1028   }
1029 }