https://github.com/akkartik/mu/blob/main/linux/raytracing/3.mu

      1 # Listing 9 of https://raytracing.github.io/books/RayTracingInOneWeekend.html
      2 #
      3 # To run (on Linux):
      4 #   $ git clone https://github.com/akkartik/mu
      5 #   $ cd mu
      6 #   $ ./translate raytracing/3.mu
      7 #   $ ./a.elf > 3.ppm
      8
      9 fn ray-color _in: (addr ray), _out: (addr rgb) {
     10   var in/esi: (addr ray) <- copy _in
     11   var out/edi: (addr rgb) <- copy _out
     12   var dir/eax: (addr vec3) <- get in, dir
     13 #?   print-string 0, "r.dir: "
     14 #?   print-vec3 0, dir
     15 #?   print-string 0, "\n"
     16   var unit-storage: vec3
     17   var unit/ecx: (addr vec3) <- address unit-storage
     18   vec3-unit dir, unit
     19 #?   print-string 0, "r.dir normalized: "
     20 #?   print-vec3 0, unit
     21 #?   print-string 0, "\n"
     22   var y-addr/eax: (addr float) <- get unit, y
     23   # t = (dir.y + 1.0) / 2.0
     24   var t/xmm0: float <- copy *y-addr
     25   var one/eax: int <- copy 1
     26   var one-f/xmm1: float <- convert one
     27   t <- add one-f
     28   var two/eax: int <- copy 2
     29   var two-f/xmm2: float <- convert two
     30   t <- divide two-f
     31 #?   print-string 0, "t: "
     32 #?   print-float-hex 0, t
     33 #?   print-string 0, "\n"
     34   # whitening = (1.0 - t) * white
     35   var whitening-storage: rgb
     36   var whitening/ecx: (addr rgb) <- address whitening-storage
     37   rgb-white whitening
     38   var one-minus-t/xmm3: float <- copy one-f
     39   one-minus-t <- subtract t
     40   rgb-scale-up whitening, one-minus-t
     41 #?   print-string 0, "whitening: "
     42 #?   print-rgb-raw 0, whitening
     43 #?   print-string 0, "\n"
     44   # out = t * (0.5, 0.7, 1.0)
     45   var dest/eax: (addr float) <- get out, r
     46   fill-in-rational dest, 5, 0xa
     47   dest <- get out, g
     48   fill-in-rational dest, 7, 0xa
     49   dest <- get out, b
     50   copy-to *dest, one-f
     51   rgb-scale-up out, t
     52 #?   print-string 0, "base: "
     53 #?   print-rgb-raw 0, out
     54 #?   print-string 0, "\n"
     55   # blend with whitening
     56   rgb-add-to out, whitening
     57 #?   print-string 0, "result: "
     58 #?   print-rgb-raw 0, out
     59 #?   print-string 0, "\n"
     60 }
     61
     62 fn main -> _/ebx: int {
     63
     64   # image
     65   #   width = 400
     66   #   height = 400 * 9/16 = 225
     67   var aspect: float
     68   var aspect-addr/eax: (addr float) <- address aspect
     69   fill-in-rational aspect-addr, 0x10, 9  # 16/9
     70 #?   print-string 0, "aspect ratio: "
     71 #?   print-float-hex 0, aspect
     72 #?   print-string 0, " "
     73 #?   {
     74 #?     var foo2/ebx: int <- reinterpret aspect
     75 #?     print-int32-hex 0, foo2
     76 #?   }
     77 #?   print-string 0, "\n"
     78
     79   # camera
     80
     81   # viewport-height = 2.0
     82   var tmp/eax: int <- copy 2
     83   var two-f/xmm4: float <- convert tmp
     84   var viewport-height/xmm7: float <- copy two-f
     85 #?   print-string 0, "viewport height: "
     86 #?   print-float-hex 0, viewport-height
     87 #?   print-string 0, " "
     88 #?   {
     89 #?     var foo: float
     90 #?     copy-to foo, viewport-height
     91 #?     var foo2/ebx: int <- reinterpret foo
     92 #?     print-int32-hex 0, foo2
     93 #?   }
     94 #?   print-string 0, "\n"
     95   # viewport-width = aspect * viewport-height
     96   var viewport-width/xmm6: float <- convert tmp
     97   viewport-width <- multiply aspect
     98 #?   print-string 0, "viewport width: "
     99 #?   print-float-hex 0, viewport-width
    100 #?   print-string 0, " "
    101 #?   {
    102 #?     var foo: float
    103 #?     copy-to foo, viewport-width
    104 #?     var foo2/ebx: int <- reinterpret foo
    105 #?     print-int32-hex 0, foo2
    106 #?   }
    107 #?   print-string 0, "\n"
    108   # focal-length = 1.0
    109   tmp <- copy 1
    110   var focal-length/xmm5: float <- convert tmp
    111
    112   # origin = point3(0, 0, 0)
    113   var origin-storage: vec3
    114   var origin/edi: (addr vec3) <- address origin-storage
    115   # horizontal = vec3(viewport-width, 0, 0)
    116   var horizontal-storage: vec3
    117   var dest/eax: (addr float) <- get horizontal-storage, x
    118   copy-to *dest, viewport-width
    119   var horizontal/ebx: (addr vec3) <- address horizontal-storage
    120   # vertical = vec3(0, viewport-height, 0)
    121   var vertical-storage: vec3
    122   dest <- get vertical-storage, y
    123   copy-to *dest, viewport-height
    124   var vertical/edx: (addr vec3) <- address vertical-storage
    125   # lower-left-corner = origin - horizontal/2 - vertical/2 - vec3(0, 0, focal-length)
    126   # . lower-left-corner = origin
    127   var lower-left-corner-storage: vec3
    128   var lower-left-corner/esi: (addr vec3) <- address lower-left-corner-storage
    129   copy-object origin, lower-left-corner
    130   # . lower-left-corner -= horizontal/2
    131   var tmp2: vec3
    132   var tmp2-addr/eax: (addr vec3) <- address tmp2
    133   copy-object horizontal, tmp2-addr
    134   vec3-scale-down tmp2-addr, two-f
    135   vec3-subtract-from lower-left-corner, tmp2-addr
    136   # . lower-left-corner -= vertical/2
    137   copy-object vertical, tmp2-addr
    138   vec3-scale-down tmp2-addr, two-f
    139   vec3-subtract-from lower-left-corner, tmp2-addr
    140   # . lower-left-corner -= vec3(0, 0, focal-length)
    141   var dest2/ecx: (addr float) <- get lower-left-corner, z
    142   var tmp3/xmm0: float <- copy *dest2
    143   tmp3 <- subtract focal-length
    144   copy-to *dest2, tmp3
    145   # phew!
    146
    147   # render
    148
    149   # live variables at this point:
    150   #   origin (edi)
    151   #   lower-left-corner (esi)
    152   #   horizontal (ebx)
    153   #   vertical (edx)
    154   # floating-point registers are all free
    155   print-string 0, "P3\n400 225\n255\n"  # 225 = image height
    156   var tmp/eax: int <- copy 0x18f # image width - 1
    157   var image-width-1/xmm7: float <- convert tmp
    158   tmp <- copy 0xe0  # image height - 1
    159   var image-height-1/xmm6: float <- convert tmp
    160   #
    161   var j/ecx: int <- copy 0xe0  # 224
    162   {
    163     compare j, 0
    164     break-if-<
    165     var i/eax: int <- copy 0
    166     {
    167       compare i, 0x190  # 400 = image width
    168       break-if->=
    169       # u = i / (image-width - 1)
    170       var u/xmm0: float <- convert i
    171       u <- divide image-width-1
    172 #?       print-string 0, "u: "
    173 #?       print-float-hex 0, u
    174 #?       print-string 0, "\n"
    175       # v = j / (image-height - 1)
    176       var v/xmm1: float <- convert j
    177       v <- divide image-height-1
    178       # r = ray(origin, lower-left-corner + u*horizontal + v*vertical - origin)
    179       var r-storage: ray
    180       # . . we're running out of int registers now,
    181       # . . but luckily we don't need i and j in the rest of this loop iteration,
    182       # . . so we'll just spill them in a block
    183       {
    184         # . r.orig = origin
    185         var r/eax: (addr ray) <- address r-storage
    186         var dest/ecx: (addr vec3) <- get r, orig
    187         copy-object origin, dest
    188         # . r.dir = lower-left-corner
    189         dest <- get r, dir
    190         copy-object lower-left-corner, dest
    191         # . r.dir += horizontal*u
    192         var tmp-vec3: vec3
    193         var tmp/eax: (addr vec3) <- address tmp-vec3
    194         copy-object horizontal, tmp
    195         vec3-scale-up tmp, u
    196         vec3-add-to dest, tmp
    197         # . r.dir += vertical*v
    198         copy-object vertical, tmp
    199         vec3-scale-up tmp, v
    200         vec3-add-to dest, tmp
    201         # . r.dir -= origin
    202         vec3-subtract-from dest, origin
    203 #?         print-string 0, "ray direction: "
    204 #?         print-vec3 0, dest
    205 #?         print-string 0, "\n"
    206       }
    207       # pixel-color = ray-color(r)
    208       var c-storage: rgb
    209       var c/ecx: (addr rgb) <- address c-storage
    210       {
    211         var r/eax: (addr ray) <- address r-storage
    212         ray-color r, c
    213         # write color
    214         print-rgb 0, c
    215 #?         print-rgb-raw 0, c
    216 #?         print-string 0, "\n"
    217       }
    218       i <- increment
    219       loop
    220     }
    221     j <- decrement
    222     loop
    223   }
    224   return 0
    225 }
    226
    227 type ray {
    228   orig: vec3  # point
    229   dir: vec3
    230 }
    231
    232 # A little different from the constructor at https://raytracing.github.io/books/RayTracingInOneWeekend.html
    233 # We immediately normalize the direction vector so we don't have to keep doing
    234 # so.
    235 fn initialize-ray _self: (addr ray), o: (addr vec3), d: (addr vec3) {
    236   var self/esi: (addr ray) <- copy _self
    237   var dest/eax: (addr vec3) <- get self, orig
    238   copy-object o, dest
    239   dest <- get self, dir
    240   vec3-unit d, dest
    241 }
    242
    243 fn ray-at _self: (addr ray), t: float, out: (addr vec3) {
    244   var self/esi: (addr ray) <- copy _self
    245   var src/eax: (addr vec3) <- get self, dir
    246   copy-object src, out
    247   vec3-scale-up out, t
    248   src <- get self, orig
    249   vec3-add-to out, src
    250 }
    251
    252 type rgb {
    253   # components normalized to within [0.0, 1.0]
    254   r: float
    255   g: float
    256   b: float
    257 }
    258
    259 # print translating to [0, 256)
    260 fn print-rgb screen: (addr screen), _c: (addr rgb) {
    261   var c/esi: (addr rgb) <- copy _c
    262   var xn: float
    263   var xn-addr/ecx: (addr float) <- address xn
    264   fill-in-rational xn-addr, 0x3e7ff, 0x3e8  # 255999 / 1000
    265   # print 255.999 * c->r
    266   var result/xmm0: float <- copy xn
    267   var src-addr/eax: (addr float) <- get c, r
    268   result <- multiply *src-addr
    269   var result-int/edx: int <- truncate result
    270   print-int32-decimal screen, result-int
    271   print-string screen, " "
    272   # print 255.999 * c->g
    273   src-addr <- get c, g
    274   result <- copy xn
    275   result <- multiply *src-addr
    276   result-int <- truncate result
    277   print-int32-decimal screen, result-int
    278   print-string screen, " "
    279   # print 255.999 * c->b
    280   src-addr <- get c, b
    281   result <- copy xn
    282   result <- multiply *src-addr
    283   result-int <- truncate result
    284   print-int32-decimal screen, result-int
    285   print-string screen, "\n"
    286 }
    287
    288 fn print-rgb-raw screen: (addr screen), _v: (addr rgb) {
    289   var v/esi: (addr rgb) <- copy _v
    290   print-string screen, "("
    291   var tmp/eax: (addr float) <- get v, r
    292   print-float-hex screen, *tmp
    293   print-string screen, ", "
    294   tmp <- get v, g
    295   print-float-hex screen, *tmp
    296   print-string screen, ", "
    297   tmp <- get v, b
    298   print-float-hex screen, *tmp
    299   print-string screen, ")"
    300 }
    301
    302 fn rgb-white _c: (addr rgb) {
    303   var c/esi: (addr rgb) <- copy _c
    304   var one/eax: int <- copy 1
    305   var one-f/xmm0: float <- convert one
    306   var dest/edi: (addr float) <- get c, r
    307   copy-to *dest, one-f
    308   dest <- get c, g
    309   copy-to *dest, one-f
    310   dest <- get c, b
    311   copy-to *dest, one-f
    312 }
    313
    314 fn rgb-add-to _c1: (addr rgb), _c2: (addr rgb) {
    315   var c1/edi: (addr rgb) <- copy _c1
    316   var c2/esi: (addr rgb) <- copy _c2
    317   # c1.r += c2.r
    318   var arg1/eax: (addr float) <- get c1, r
    319   var arg2/ecx: (addr float) <- get c2, r
    320   var result/xmm0: float <- copy *arg1
    321   result <- add *arg2
    322   copy-to *arg1, result
    323   # c1.g += c2.g
    324   arg1 <- get c1, g
    325   arg2 <- get c2, g
    326   result <- copy *arg1
    327   result <- add *arg2
    328   copy-to *arg1, result
    329   # c1.b += c2.b
    330   arg1 <- get c1, b
    331   arg2 <- get c2, b
    332   result <- copy *arg1
    333   result <- add *arg2
    334   copy-to *arg1, result
    335 }
    336
    337 fn rgb-scale-up _c1: (addr rgb), f: float {
    338   var c1/edi: (addr rgb) <- copy _c1
    339   # c1.r *= f
    340   var dest/eax: (addr float) <- get c1, r
    341   var result/xmm0: float <- copy *dest
    342   result <- multiply f
    343   copy-to *dest, result
    344   # c1.g *= f
    345   dest <- get c1, g
    346   result <- copy *dest
    347   result <- multiply f
    348   copy-to *dest, result
    349   # c1.b *= f
    350   dest <- get c1, b
    351   result <- copy *dest
    352   result <- multiply f
    353   copy-to *dest, result
    354 }
    355
    356 type vec3 {
    357   x: float
    358   y: float
    359   z: float
    360 }
    361
    362 fn print-vec3 screen: (addr screen), _v: (addr vec3) {
    363   var v/esi: (addr vec3) <- copy _v
    364   print-string screen, "("
    365   var tmp/eax: (addr float) <- get v, x
    366   print-float-hex screen, *tmp
    367   print-string screen, ", "
    368   tmp <- get v, y
    369   print-float-hex screen, *tmp
    370   print-string screen, ", "
    371   tmp <- get v, z
    372   print-float-hex screen, *tmp
    373   print-string screen, ")"
    374 }
    375
    376 fn vec3-add-to _v1: (addr vec3), _v2: (addr vec3) {
    377   var v1/edi: (addr vec3) <- copy _v1
    378   var v2/esi: (addr vec3) <- copy _v2
    379   # v1.x += v2.x
    380   var arg1/eax: (addr float) <- get v1, x
    381   var arg2/ecx: (addr float) <- get v2, x
    382   var result/xmm0: float <- copy *arg1
    383   result <- add *arg2
    384   copy-to *arg1, result
    385   # v1.y += v2.y
    386   arg1 <- get v1, y
    387   arg2 <- get v2, y
    388   result <- copy *arg1
    389   result <- add *arg2
    390   copy-to *arg1, result
    391   # v1.z += v2.z
    392   arg1 <- get v1, z
    393   arg2 <- get v2, z
    394   result <- copy *arg1
    395   result <- add *arg2
    396   copy-to *arg1, result
    397 }
    398
    399 fn vec3-subtract-from v1: (addr vec3), v2: (addr vec3) {
    400   var tmp-storage: vec3
    401   var tmp/eax: (addr vec3) <- address tmp-storage
    402   copy-object v2, tmp
    403   vec3-negate tmp
    404   vec3-add-to v1, tmp
    405 }
    406
    407 fn vec3-negate v: (addr vec3) {
    408   var negative-one/eax: int <- copy -1
    409   var negative-one-f/xmm0: float <- convert negative-one
    410   vec3-scale-up v, negative-one-f
    411 }
    412
    413 fn vec3-scale-up _v: (addr vec3), f: float {
    414   var v/edi: (addr vec3) <- copy _v
    415   # v.x *= f
    416   var dest/eax: (addr float) <- get v, x
    417   var result/xmm0: float <- copy *dest
    418   result <- multiply f
    419   copy-to *dest, result
    420   # v.y *= f
    421   dest <- get v, y
    422   result <- copy *dest
    423   result <- multiply f
    424   copy-to *dest, result
    425   # v.z *= f
    426   dest <- get v, z
    427   result <- copy *dest
    428   result <- multiply f
    429   copy-to *dest, result
    430 }
    431
    432 fn vec3-scale-down _v: (addr vec3), f: float {
    433   var v/edi: (addr vec3) <- copy _v
    434   # v.x /= f
    435   var dest/eax: (addr float) <- get v, x
    436   var result/xmm0: float <- copy *dest
    437   result <- divide f
    438   copy-to *dest, result
    439   # v.y /= f
    440   dest <- get v, y
    441   result <- copy *dest
    442   result <- divide f
    443   copy-to *dest, result
    444   # v.z /= f
    445   dest <- get v, z
    446   result <- copy *dest
    447   result <- divide f
    448   copy-to *dest, result
    449 }
    450
    451 fn vec3-unit in: (addr vec3), out: (addr vec3) {
    452   var len/xmm0: float <- vec3-length in
    453 #?   print-string 0, "len: "
    454 #?   print-float-hex 0, len
    455 #?   print-string 0, "\n"
    456   copy-object in, out
    457   vec3-scale-down out, len
    458 }
    459
    460 fn vec3-length v: (addr vec3) -> _/xmm0: float {
    461   var result/xmm0: float <- vec3-length-squared v
    462   result <- square-root result
    463   return result
    464 }
    465
    466 fn vec3-length-squared _v: (addr vec3) -> _/xmm0: float {
    467   var v/esi: (addr vec3) <- copy _v
    468   # result = v.x * v.x
    469   var src/eax: (addr float) <- get v, x
    470   var tmp/xmm1: float <- copy *src
    471   tmp <- multiply tmp
    472   var result/xmm0: float <- copy tmp
    473   # result += v.y * v.y
    474   src <- get v, y
    475   tmp <- copy *src
    476   tmp <- multiply tmp
    477   result <- add tmp
    478   # result += v.z * v.z
    479   src <- get v, z
    480   tmp <- copy *src
    481   tmp <- multiply tmp
    482   result <- add tmp
    483   return result
    484 }