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 }