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 }