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