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