From 8679001f5c54a298d999df8c76318c5bd105c636 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Wed, 14 Jul 2021 01:54:25 -0700 Subject: . --- html/img.mu.html | 1217 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1217 insertions(+) create mode 100644 html/img.mu.html (limited to 'html/img.mu.html') diff --git a/html/img.mu.html b/html/img.mu.html new file mode 100644 index 00000000..19bd7959 --- /dev/null +++ b/html/img.mu.html @@ -0,0 +1,1217 @@ + + + + +Mu - img.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/img.mu +
+   1 # load an image from disk and display it on screen
+   2 #
+   3 # To build:
+   4 #   $ ./translate shell/*.mu                        # generates code.img
+   5 # Load a pbm, pgm or ppm image (no more than 255 levels)
+   6 #   $ dd if=/dev/zero of=data.img count=20160
+   7 #   $ cat x.pbm |dd of=data.img conv=notrunc
+   8 # or
+   9 #   $ cat t.pgm |dd of=data.img conv=notrunc
+  10 # or
+  11 #   $ cat snail.ppm |dd of=data.img conv=notrunc
+  12 # To run:
+  13 #   $ qemu-system-i386 -hda code.img -hdb data.img
+  14 
+  15 type image {
+  16   type: int  # supported types:
+  17              #  1: portable bitmap (P1) - pixels 0 or 1
+  18              #  2: portable greymap (P2) - pixels 1-byte greyscale values
+  19              #  3: portable pixmap (P3) - pixels 3-byte rgb values
+  20   max: int
+  21   width: int
+  22   height: int
+  23   data: (handle array byte)
+  24 }
+  25 
+  26 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+  27   var img-storage: image
+  28   var img/esi: (addr image) <- address img-storage
+  29   load-image img, data-disk
+  30   render-image screen, img, 0/x, 0/y, 0x300/width, 0x300/height
+  31 }
+  32 
+  33 fn load-image self: (addr image), data-disk: (addr disk) {
+  34   # data-disk -> stream
+  35   var s-storage: (stream byte 0x200000)  # 512* 0x1000 sectors
+  36   var s/ebx: (addr stream byte) <- address s-storage
+  37   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "loading sectors from data disk", 3/fg, 0/bg
+  38   move-cursor-to-left-margin-of-next-line 0/screen
+  39   load-sectors data-disk, 0/lba, 0x100/sectors, s
+  40   load-sectors data-disk, 0x100/lba, 0x100/sectors, s
+  41   load-sectors data-disk, 0x200/lba, 0x100/sectors, s
+  42   load-sectors data-disk, 0x300/lba, 0x100/sectors, s
+  43   load-sectors data-disk, 0x400/lba, 0x100/sectors, s
+  44   load-sectors data-disk, 0x500/lba, 0x100/sectors, s
+  45   load-sectors data-disk, 0x600/lba, 0x100/sectors, s
+  46   load-sectors data-disk, 0x700/lba, 0x100/sectors, s
+  47   load-sectors data-disk, 0x800/lba, 0x100/sectors, s
+  48   load-sectors data-disk, 0x900/lba, 0x100/sectors, s
+  49   load-sectors data-disk, 0xa00/lba, 0x100/sectors, s
+  50   load-sectors data-disk, 0xb00/lba, 0x100/sectors, s
+  51   load-sectors data-disk, 0xc00/lba, 0x100/sectors, s
+  52   load-sectors data-disk, 0xd00/lba, 0x100/sectors, s
+  53   load-sectors data-disk, 0xe00/lba, 0x100/sectors, s
+  54   load-sectors data-disk, 0xf00/lba, 0x100/sectors, s
+  55   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "parsing", 3/fg, 0/bg
+  56   move-cursor-to-left-margin-of-next-line 0/screen
+  57   initialize-image self, s
+  58 }
+  59 
+  60 fn initialize-image _self: (addr image), in: (addr stream byte) {
+  61   var self/esi: (addr image) <- copy _self
+  62   var mode-storage: slice
+  63   var mode/ecx: (addr slice) <- address mode-storage
+  64   next-word in, mode
+  65   {
+  66     var P1?/eax: boolean <- slice-equal? mode, "P1"
+  67     compare P1?, 0/false
+  68     break-if-=
+  69     var type-a/eax: (addr int) <- get self, type
+  70     copy-to *type-a, 1/ppm
+  71     initialize-image-from-pbm self, in
+  72     return
+  73   }
+  74   {
+  75     var P2?/eax: boolean <- slice-equal? mode, "P2"
+  76     compare P2?, 0/false
+  77     break-if-=
+  78     var type-a/eax: (addr int) <- get self, type
+  79     copy-to *type-a, 2/pgm
+  80     initialize-image-from-pgm self, in
+  81     return
+  82   }
+  83   {
+  84     var P3?/eax: boolean <- slice-equal? mode, "P3"
+  85     compare P3?, 0/false
+  86     break-if-=
+  87     var type-a/eax: (addr int) <- get self, type
+  88     copy-to *type-a, 3/ppm
+  89     initialize-image-from-ppm self, in
+  90     return
+  91   }
+  92   abort "initialize-image: unrecognized image type"
+  93 }
+  94 
+  95 # dispatch to a few variants with mostly identical boilerplate
+  96 fn render-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
+  97   var img/esi: (addr image) <- copy _img
+  98   var type-a/eax: (addr int) <- get img, type
+  99   {
+ 100     compare *type-a, 1/pbm
+ 101     break-if-!=
+ 102     render-pbm-image screen, img, xmin, ymin, width, height
+ 103     return
+ 104   }
+ 105   {
+ 106     compare *type-a, 2/pgm
+ 107     break-if-!=
+ 108     var img2-storage: image
+ 109     var img2/edi: (addr image) <- address img2-storage
+ 110     dither-pgm-unordered img, img2
+ 111     render-raw-image screen, img2, xmin, ymin, width, height
+ 112     return
+ 113   }
+ 114   {
+ 115     compare *type-a, 3/ppm
+ 116     break-if-!=
+ 117     var img2-storage: image
+ 118     var img2/edi: (addr image) <- address img2-storage
+ 119     dither-ppm-unordered img, img2
+ 120     render-raw-image screen, img2, xmin, ymin, width, height
+ 121     return
+ 122   }
+ 123   abort "render-image: unrecognized image type"
+ 124 }
+ 125 
+ 126 ## helpers
+ 127 
+ 128 # import a black-and-white ascii bitmap (each pixel is 0 or 1)
+ 129 fn initialize-image-from-pbm _self: (addr image), in: (addr stream byte) {
+ 130   var self/esi: (addr image) <- copy _self
+ 131   var curr-word-storage: slice
+ 132   var curr-word/ecx: (addr slice) <- address curr-word-storage
+ 133   # load width, height
+ 134   next-word in, curr-word
+ 135   var tmp/eax: int <- parse-decimal-int-from-slice curr-word
+ 136   var width/edx: int <- copy tmp
+ 137   next-word in, curr-word
+ 138   tmp <- parse-decimal-int-from-slice curr-word
+ 139   var height/ebx: int <- copy tmp
+ 140   # save width, height
+ 141   var dest/eax: (addr int) <- get self, width
+ 142   copy-to *dest, width
+ 143   dest <- get self, height
+ 144   copy-to *dest, height
+ 145   # initialize data
+ 146   var capacity/edx: int <- copy width
+ 147   capacity <- multiply height
+ 148   var data-ah/edi: (addr handle array byte) <- get self, data
+ 149   populate data-ah, capacity
+ 150   var _data/eax: (addr array byte) <- lookup *data-ah
+ 151   var data/edi: (addr array byte) <- copy _data
+ 152   var i/ebx: int <- copy 0
+ 153   {
+ 154     compare i, capacity
+ 155     break-if->=
+ 156     next-word in, curr-word
+ 157     var src/eax: int <- parse-decimal-int-from-slice curr-word
+ 158     {
+ 159       var dest/ecx: (addr byte) <- index data, i
+ 160       copy-byte-to *dest, src
+ 161     }
+ 162     i <- increment
+ 163     loop
+ 164   }
+ 165 }
+ 166 
+ 167 # render a black-and-white ascii bitmap (each pixel is 0 or 1)
+ 168 fn render-pbm-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
+ 169   var img/esi: (addr image) <- copy _img
+ 170   # yratio = height/img->height
+ 171   var img-height-a/eax: (addr int) <- get img, height
+ 172   var img-height/xmm0: float <- convert *img-height-a
+ 173   var yratio/xmm1: float <- convert height
+ 174   yratio <- divide img-height
+ 175   # xratio = width/img->width
+ 176   var img-width-a/eax: (addr int) <- get img, width
+ 177   var img-width/ebx: int <- copy *img-width-a
+ 178   var img-width-f/xmm0: float <- convert img-width
+ 179   var xratio/xmm2: float <- convert width
+ 180   xratio <- divide img-width-f
+ 181   # esi = img->data
+ 182   var img-data-ah/eax: (addr handle array byte) <- get img, data
+ 183   var _img-data/eax: (addr array byte) <- lookup *img-data-ah
+ 184   var img-data/esi: (addr array byte) <- copy _img-data
+ 185   var len/edi: int <- length img-data
+ 186   #
+ 187   var one/eax: int <- copy 1
+ 188   var one-f/xmm3: float <- convert one
+ 189   var width-f/xmm4: float <- convert width
+ 190   var height-f/xmm5: float <- convert height
+ 191   var zero/eax: int <- copy 0
+ 192   var zero-f/xmm0: float <- convert zero
+ 193   var y/xmm6: float <- copy zero-f
+ 194   {
+ 195     compare y, height-f
+ 196     break-if-float>=
+ 197     var imgy-f/xmm5: float <- copy y
+ 198     imgy-f <- divide yratio
+ 199     var imgy/edx: int <- truncate imgy-f
+ 200     var x/xmm7: float <- copy zero-f
+ 201     {
+ 202       compare x, width-f
+ 203       break-if-float>=
+ 204       var imgx-f/xmm5: float <- copy x
+ 205       imgx-f <- divide xratio
+ 206       var imgx/ecx: int <- truncate imgx-f
+ 207       var idx/eax: int <- copy imgy
+ 208       idx <- multiply img-width
+ 209       idx <- add imgx
+ 210       # error info in case we rounded wrong and 'index' will fail bounds-check
+ 211       compare idx, len
+ 212       {
+ 213         break-if-<
+ 214         set-cursor-position 0/screen, 0x20/x 0x20/y
+ 215         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg
+ 216         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg
+ 217         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg
+ 218       }
+ 219       var src-a/eax: (addr byte) <- index img-data, idx
+ 220       var src/eax: byte <- copy-byte *src-a
+ 221       var color-int/eax: int <- copy src
+ 222       {
+ 223         compare color-int, 0/black
+ 224         break-if-=
+ 225         color-int <- copy 0xf/white
+ 226       }
+ 227       var screenx/ecx: int <- convert x
+ 228       screenx <- add xmin
+ 229       var screeny/edx: int <- convert y
+ 230       screeny <- add ymin
+ 231       pixel screen, screenx, screeny, color-int
+ 232       x <- add one-f
+ 233       loop
+ 234     }
+ 235     y <- add one-f
+ 236     loop
+ 237   }
+ 238 }
+ 239 
+ 240 # import a greyscale ascii "greymap" (each pixel is a shade of grey from 0 to 255)
+ 241 fn initialize-image-from-pgm _self: (addr image), in: (addr stream byte) {
+ 242   var self/esi: (addr image) <- copy _self
+ 243   var curr-word-storage: slice
+ 244   var curr-word/ecx: (addr slice) <- address curr-word-storage
+ 245   # load width, height
+ 246   next-word in, curr-word
+ 247   var tmp/eax: int <- parse-decimal-int-from-slice curr-word
+ 248   var width/edx: int <- copy tmp
+ 249   next-word in, curr-word
+ 250   tmp <- parse-decimal-int-from-slice curr-word
+ 251   var height/ebx: int <- copy tmp
+ 252   # check and save color levels
+ 253   next-word in, curr-word
+ 254   {
+ 255     tmp <- parse-decimal-int-from-slice curr-word
+ 256     compare tmp, 0xff
+ 257     break-if-=
+ 258     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "levels of grey is not 255; continuing and hoping for the best", 0x2b/fg 0/bg
+ 259   }
+ 260   var dest/edi: (addr int) <- get self, max
+ 261   copy-to *dest, tmp
+ 262   # save width, height
+ 263   dest <- get self, width
+ 264   copy-to *dest, width
+ 265   dest <- get self, height
+ 266   copy-to *dest, height
+ 267   # initialize data
+ 268   var capacity/edx: int <- copy width
+ 269   capacity <- multiply height
+ 270   var data-ah/edi: (addr handle array byte) <- get self, data
+ 271   populate data-ah, capacity
+ 272   var _data/eax: (addr array byte) <- lookup *data-ah
+ 273   var data/edi: (addr array byte) <- copy _data
+ 274   var i/ebx: int <- copy 0
+ 275   {
+ 276     compare i, capacity
+ 277     break-if->=
+ 278     next-word in, curr-word
+ 279     var src/eax: int <- parse-decimal-int-from-slice curr-word
+ 280     {
+ 281       var dest/ecx: (addr byte) <- index data, i
+ 282       copy-byte-to *dest, src
+ 283     }
+ 284     i <- increment
+ 285     loop
+ 286   }
+ 287 }
+ 288 
+ 289 # render a greyscale ascii "greymap" (each pixel is a shade of grey from 0 to 255) by quantizing the shades
+ 290 fn render-pgm-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
+ 291   var img/esi: (addr image) <- copy _img
+ 292   # yratio = height/img->height
+ 293   var img-height-a/eax: (addr int) <- get img, height
+ 294   var img-height/xmm0: float <- convert *img-height-a
+ 295   var yratio/xmm1: float <- convert height
+ 296   yratio <- divide img-height
+ 297   # xratio = width/img->width
+ 298   var img-width-a/eax: (addr int) <- get img, width
+ 299   var img-width/ebx: int <- copy *img-width-a
+ 300   var img-width-f/xmm0: float <- convert img-width
+ 301   var xratio/xmm2: float <- convert width
+ 302   xratio <- divide img-width-f
+ 303   # esi = img->data
+ 304   var img-data-ah/eax: (addr handle array byte) <- get img, data
+ 305   var _img-data/eax: (addr array byte) <- lookup *img-data-ah
+ 306   var img-data/esi: (addr array byte) <- copy _img-data
+ 307   var len/edi: int <- length img-data
+ 308   #
+ 309   var one/eax: int <- copy 1
+ 310   var one-f/xmm3: float <- convert one
+ 311   var width-f/xmm4: float <- convert width
+ 312   var height-f/xmm5: float <- convert height
+ 313   var zero/eax: int <- copy 0
+ 314   var zero-f/xmm0: float <- convert zero
+ 315   var y/xmm6: float <- copy zero-f
+ 316   {
+ 317     compare y, height-f
+ 318     break-if-float>=
+ 319     var imgy-f/xmm5: float <- copy y
+ 320     imgy-f <- divide yratio
+ 321     var imgy/edx: int <- truncate imgy-f
+ 322     var x/xmm7: float <- copy zero-f
+ 323     {
+ 324       compare x, width-f
+ 325       break-if-float>=
+ 326       var imgx-f/xmm5: float <- copy x
+ 327       imgx-f <- divide xratio
+ 328       var imgx/ecx: int <- truncate imgx-f
+ 329       var idx/eax: int <- copy imgy
+ 330       idx <- multiply img-width
+ 331       idx <- add imgx
+ 332       # error info in case we rounded wrong and 'index' will fail bounds-check
+ 333       compare idx, len
+ 334       {
+ 335         break-if-<
+ 336         set-cursor-position 0/screen, 0x20/x 0x20/y
+ 337         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg
+ 338         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg
+ 339         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg
+ 340       }
+ 341       var src-a/eax: (addr byte) <- index img-data, idx
+ 342       var src/eax: byte <- copy-byte *src-a
+ 343       var color-int/eax: int <- nearest-grey src
+ 344       var screenx/ecx: int <- convert x
+ 345       screenx <- add xmin
+ 346       var screeny/edx: int <- convert y
+ 347       screeny <- add ymin
+ 348       pixel screen, screenx, screeny, color-int
+ 349       x <- add one-f
+ 350       loop
+ 351     }
+ 352     y <- add one-f
+ 353     loop
+ 354   }
+ 355 }
+ 356 
+ 357 fn nearest-grey level-255: byte -> _/eax: int {
+ 358   var result/eax: int <- copy level-255
+ 359   result <- shift-right 4
+ 360   result <- add 0x10
+ 361   return result
+ 362 }
+ 363 
+ 364 fn dither-pgm-unordered-monochrome _src: (addr image), _dest: (addr image) {
+ 365   var src/esi: (addr image) <- copy _src
+ 366   var dest/edi: (addr image) <- copy _dest
+ 367   # copy 'width'
+ 368   var src-width-a/eax: (addr int) <- get src, width
+ 369   var tmp/eax: int <- copy *src-width-a
+ 370   var src-width: int
+ 371   copy-to src-width, tmp
+ 372   {
+ 373     var dest-width-a/edx: (addr int) <- get dest, width
+ 374     copy-to *dest-width-a, tmp
+ 375   }
+ 376   # copy 'height'
+ 377   var src-height-a/eax: (addr int) <- get src, height
+ 378   var tmp/eax: int <- copy *src-height-a
+ 379   var src-height: int
+ 380   copy-to src-height, tmp
+ 381   {
+ 382     var dest-height-a/ecx: (addr int) <- get dest, height
+ 383     copy-to *dest-height-a, tmp
+ 384   }
+ 385   # transform 'data'
+ 386   var capacity/ebx: int <- copy src-width
+ 387   capacity <- multiply src-height
+ 388   var dest/edi: (addr image) <- copy _dest
+ 389   var dest-data-ah/eax: (addr handle array byte) <- get dest, data
+ 390   populate dest-data-ah, capacity
+ 391   var _dest-data/eax: (addr array byte) <- lookup *dest-data-ah
+ 392   var dest-data/edi: (addr array byte) <- copy _dest-data
+ 393   # needs a buffer to temporarily hold more than 256 levels of precision
+ 394   var errors-storage: (array int 0xc0000)
+ 395   var errors/ebx: (addr array int) <- address errors-storage
+ 396   var src-data-ah/eax: (addr handle array byte) <- get src, data
+ 397   var _src-data/eax: (addr array byte) <- lookup *src-data-ah
+ 398   var src-data/esi: (addr array byte) <- copy _src-data
+ 399   var y/edx: int <- copy 0
+ 400   {
+ 401     compare y, src-height
+ 402     break-if->=
+ 403     var x/ecx: int <- copy 0
+ 404     {
+ 405       compare x, src-width
+ 406       break-if->=
+ 407       var curr/eax: byte <- _read-pgm-buffer src-data, x, y, src-width
+ 408       var curr-int/eax: int <- copy curr
+ 409       curr-int <- shift-left 0x10  # we have 32 bits; we'll use 16 bits for the fraction and leave 8 for unanticipated overflow
+ 410       var error/esi: int <- _read-dithering-error errors, x, y, src-width
+ 411       error <- add curr-int
+ 412       $_dither-pgm-unordered-monochrome:update-error: {
+ 413         compare error, 0x800000
+ 414         {
+ 415           break-if->=
+ 416           _write-raw-buffer dest-data, x, y, src-width, 0/black
+ 417           break $_dither-pgm-unordered-monochrome:update-error
+ 418         }
+ 419         _write-raw-buffer dest-data, x, y, src-width, 1/white
+ 420         error <- subtract 0xff0000
+ 421       }
+ 422       _diffuse-dithering-error-floyd-steinberg errors, x, y, src-width, src-height, error
+ 423       x <- increment
+ 424       loop
+ 425     }
+ 426     move-cursor-to-left-margin-of-next-line 0/screen
+ 427     y <- increment
+ 428     loop
+ 429   }
+ 430 }
+ 431 
+ 432 fn dither-pgm-unordered _src: (addr image), _dest: (addr image) {
+ 433   var src/esi: (addr image) <- copy _src
+ 434   var dest/edi: (addr image) <- copy _dest
+ 435   # copy 'width'
+ 436   var src-width-a/eax: (addr int) <- get src, width
+ 437   var tmp/eax: int <- copy *src-width-a
+ 438   var src-width: int
+ 439   copy-to src-width, tmp
+ 440   {
+ 441     var dest-width-a/edx: (addr int) <- get dest, width
+ 442     copy-to *dest-width-a, tmp
+ 443   }
+ 444   # copy 'height'
+ 445   var src-height-a/eax: (addr int) <- get src, height
+ 446   var tmp/eax: int <- copy *src-height-a
+ 447   var src-height: int
+ 448   copy-to src-height, tmp
+ 449   {
+ 450     var dest-height-a/ecx: (addr int) <- get dest, height
+ 451     copy-to *dest-height-a, tmp
+ 452   }
+ 453   # compute scaling factor 255/max
+ 454   var target-scale/eax: int <- copy 0xff
+ 455   var scale-f/xmm7: float <- convert target-scale
+ 456   var src-max-a/eax: (addr int) <- get src, max
+ 457   var tmp-f/xmm0: float <- convert *src-max-a
+ 458   scale-f <- divide tmp-f
+ 459   # transform 'data'
+ 460   var capacity/ebx: int <- copy src-width
+ 461   capacity <- multiply src-height
+ 462   var dest/edi: (addr image) <- copy _dest
+ 463   var dest-data-ah/eax: (addr handle array byte) <- get dest, data
+ 464   populate dest-data-ah, capacity
+ 465   var _dest-data/eax: (addr array byte) <- lookup *dest-data-ah
+ 466   var dest-data/edi: (addr array byte) <- copy _dest-data
+ 467   # needs a buffer to temporarily hold more than 256 levels of precision
+ 468   var errors-storage: (array int 0xc0000)
+ 469   var errors/ebx: (addr array int) <- address errors-storage
+ 470   var src-data-ah/eax: (addr handle array byte) <- get src, data
+ 471   var _src-data/eax: (addr array byte) <- lookup *src-data-ah
+ 472   var src-data/esi: (addr array byte) <- copy _src-data
+ 473   var y/edx: int <- copy 0
+ 474   {
+ 475     compare y, src-height
+ 476     break-if->=
+ 477     var x/ecx: int <- copy 0
+ 478     {
+ 479       compare x, src-width
+ 480       break-if->=
+ 481       var initial-color/eax: byte <- _read-pgm-buffer src-data, x, y, src-width
+ 482       # . scale to 255 levels
+ 483       var initial-color-int/eax: int <- copy initial-color
+ 484       var initial-color-f/xmm0: float <- convert initial-color-int
+ 485       initial-color-f <- multiply scale-f
+ 486       initial-color-int <- convert initial-color-f
+ 487       var error/esi: int <- _read-dithering-error errors, x, y, src-width
+ 488       # error += (initial-color << 16)
+ 489       {
+ 490         var tmp/eax: int <- copy initial-color-int
+ 491         tmp <- shift-left 0x10  # we have 32 bits; we'll use 16 bits for the fraction and leave 8 for unanticipated overflow
+ 492         error <- add tmp
+ 493       }
+ 494       # nearest-color = nearest(error >> 16)
+ 495       var nearest-color/eax: int <- copy error
+ 496       nearest-color <- shift-right-signed 0x10
+ 497       {
+ 498         compare nearest-color, 0
+ 499         break-if->=
+ 500         nearest-color <- copy 0
+ 501       }
+ 502       {
+ 503         compare nearest-color, 0xf0
+ 504         break-if-<=
+ 505         nearest-color <- copy 0xf0
+ 506       }
+ 507       # . truncate last 4 bits
+ 508       nearest-color <- and 0xf0
+ 509       # error -= (nearest-color << 16)
+ 510       {
+ 511         var tmp/eax: int <- copy nearest-color
+ 512         tmp <- shift-left 0x10
+ 513         error <- subtract tmp
+ 514       }
+ 515       # color-index = (nearest-color >> 4 + 16)
+ 516       var color-index/eax: int <- copy nearest-color
+ 517       color-index <- shift-right 4
+ 518       color-index <- add 0x10
+ 519       var color-index-byte/eax: byte <- copy-byte color-index
+ 520       _write-raw-buffer dest-data, x, y, src-width, color-index-byte
+ 521       _diffuse-dithering-error-floyd-steinberg errors, x, y, src-width, src-height, error
+ 522       x <- increment
+ 523       loop
+ 524     }
+ 525     y <- increment
+ 526     loop
+ 527   }
+ 528 }
+ 529 
+ 530 # Use Floyd-Steinberg algorithm for diffusing error at x, y in a 2D grid of
+ 531 # dimensions (width, height)
+ 532 #
+ 533 # https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html
+ 534 #
+ 535 # Error is currently a fixed-point number with 16-bit fraction. But
+ 536 # interestingly this function doesn't care about that.
+ 537 fn _diffuse-dithering-error-floyd-steinberg errors: (addr array int), x: int, y: int, width: int, height: int, error: int {
+ 538   {
+ 539     compare error, 0
+ 540     break-if-!=
+ 541     return
+ 542   }
+ 543   var width-1/esi: int <- copy width
+ 544   width-1 <- decrement
+ 545   var height-1/edi: int <- copy height
+ 546   height-1 <- decrement
+ 547   # delta = error/16
+ 548 #?   show-errors errors, width, height, x, y
+ 549   var delta/ecx: int <- copy error
+ 550   delta <- shift-right-signed 4
+ 551   # In Floyd-Steinberg, each pixel X transmits its errors to surrounding
+ 552   # pixels in the following proportion:
+ 553   #           X     7/16
+ 554   #     3/16  5/16  1/16
+ 555   var x/edx: int <- copy x
+ 556   {
+ 557     compare x, width-1
+ 558     break-if->=
+ 559     var tmp/eax: int <- copy 7
+ 560     tmp <- multiply delta
+ 561     var xright/edx: int <- copy x
+ 562     xright <- increment
+ 563     _accumulate-dithering-error errors, xright, y, width, tmp
+ 564   }
+ 565   var y/ebx: int <- copy y
+ 566   {
+ 567     compare y, height-1
+ 568     break-if-<
+ 569     return
+ 570   }
+ 571   var ybelow: int
+ 572   copy-to ybelow, y
+ 573   increment ybelow
+ 574   {
+ 575     compare x, 0
+ 576     break-if-<=
+ 577     var tmp/eax: int <- copy 3
+ 578     tmp <- multiply delta
+ 579     var xleft/edx: int <- copy x
+ 580     xleft <- decrement
+ 581     _accumulate-dithering-error errors, xleft, ybelow, width, tmp
+ 582   }
+ 583   {
+ 584     var tmp/eax: int <- copy 5
+ 585     tmp <- multiply delta
+ 586     _accumulate-dithering-error errors, x, ybelow, width, tmp
+ 587   }
+ 588   {
+ 589     compare x, width-1
+ 590     break-if->=
+ 591     var xright/edx: int <- copy x
+ 592     xright <- increment
+ 593     _accumulate-dithering-error errors, xright, ybelow, width, delta
+ 594   }
+ 595 #?   show-errors errors, width, height, x, y
+ 596 }
+ 597 
+ 598 fn _accumulate-dithering-error errors: (addr array int), x: int, y: int, width: int, error: int {
+ 599   var curr/esi: int <- _read-dithering-error errors, x, y, width
+ 600   curr <- add error
+ 601   _write-dithering-error errors, x, y, width, curr
+ 602 }
+ 603 
+ 604 fn _read-dithering-error _errors: (addr array int), x: int, y: int, width: int -> _/esi: int {
+ 605   var errors/esi: (addr array int) <- copy _errors
+ 606   var idx/ecx: int <- copy y
+ 607   idx <- multiply width
+ 608   idx <- add x
+ 609   var result-a/eax: (addr int) <- index errors, idx
+ 610   return *result-a
+ 611 }
+ 612 
+ 613 fn _write-dithering-error _errors: (addr array int), x: int, y: int, width: int, val: int {
+ 614   var errors/esi: (addr array int) <- copy _errors
+ 615   var idx/ecx: int <- copy y
+ 616   idx <- multiply width
+ 617   idx <- add x
+ 618 #?   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 7/fg 0/bg
+ 619 #?   move-cursor-to-left-margin-of-next-line 0/screen
+ 620   var src/eax: int <- copy val
+ 621   var dest-a/edi: (addr int) <- index errors, idx
+ 622   copy-to *dest-a, src
+ 623 }
+ 624 
+ 625 fn _read-pgm-buffer _buf: (addr array byte), x: int, y: int, width: int -> _/eax: byte {
+ 626   var buf/esi: (addr array byte) <- copy _buf
+ 627   var idx/ecx: int <- copy y
+ 628   idx <- multiply width
+ 629   idx <- add x
+ 630   var result-a/eax: (addr byte) <- index buf, idx
+ 631   var result/eax: byte <- copy-byte *result-a
+ 632   return result
+ 633 }
+ 634 
+ 635 fn _write-raw-buffer _buf: (addr array byte), x: int, y: int, width: int, val: byte {
+ 636   var buf/esi: (addr array byte) <- copy _buf
+ 637   var idx/ecx: int <- copy y
+ 638   idx <- multiply width
+ 639   idx <- add x
+ 640   var src/eax: byte <- copy val
+ 641   var dest-a/edi: (addr byte) <- index buf, idx
+ 642   copy-byte-to *dest-a, src
+ 643 }
+ 644 
+ 645 # some debugging helpers
+ 646 fn show-errors errors: (addr array int), width: int, height: int, x: int, y: int {
+ 647   compare y, 1
+ 648   {
+ 649     break-if-=
+ 650     return
+ 651   }
+ 652   compare x, 0
+ 653   {
+ 654     break-if-=
+ 655     return
+ 656   }
+ 657   var y/edx: int <- copy 0
+ 658   {
+ 659     compare y, height
+ 660     break-if->=
+ 661     var x/ecx: int <- copy 0
+ 662     {
+ 663       compare x, width
+ 664       break-if->=
+ 665       var error/esi: int <- _read-dithering-error errors, x, y, width
+ 666       psd "e", error, 5/fg, x, y
+ 667       x <- increment
+ 668       loop
+ 669     }
+ 670     move-cursor-to-left-margin-of-next-line 0/screen
+ 671     y <- increment
+ 672     loop
+ 673   }
+ 674 }
+ 675 
+ 676 fn psd s: (addr array byte), d: int, fg: int, x: int, y: int {
+ 677   {
+ 678     compare y, 0x18
+ 679     break-if->=
+ 680     return
+ 681   }
+ 682   {
+ 683     compare y, 0x1c
+ 684     break-if-<=
+ 685     return
+ 686   }
+ 687   {
+ 688     compare x, 0x40
+ 689     break-if->=
+ 690     return
+ 691   }
+ 692 #?   {
+ 693 #?     compare x, 0x48
+ 694 #?     break-if-<=
+ 695 #?     return
+ 696 #?   }
+ 697   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, s, 7/fg 0/bg
+ 698   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, d, fg 0/bg
+ 699 }
+ 700 
+ 701 fn psx s: (addr array byte), d: int, fg: int, x: int, y: int {
+ 702 #?   {
+ 703 #?     compare y, 0x60
+ 704 #?     break-if->=
+ 705 #?     return
+ 706 #?   }
+ 707 #?   {
+ 708 #?     compare y, 0x6c
+ 709 #?     break-if-<=
+ 710 #?     return
+ 711 #?   }
+ 712   {
+ 713     compare x, 0x20
+ 714     break-if->=
+ 715     return
+ 716   }
+ 717 #?   {
+ 718 #?     compare x, 0x6c
+ 719 #?     break-if-<=
+ 720 #?     return
+ 721 #?   }
+ 722   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, s, 7/fg 0/bg
+ 723   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, d, fg 0/bg
+ 724 }
+ 725 
+ 726 # import a color ascii "pixmap" (each pixel consists of 3 shades of r/g/b from 0 to 255)
+ 727 fn initialize-image-from-ppm _self: (addr image), in: (addr stream byte) {
+ 728   var self/esi: (addr image) <- copy _self
+ 729   var curr-word-storage: slice
+ 730   var curr-word/ecx: (addr slice) <- address curr-word-storage
+ 731   # load width, height
+ 732   next-word in, curr-word
+ 733   var tmp/eax: int <- parse-decimal-int-from-slice curr-word
+ 734   var width/edx: int <- copy tmp
+ 735   next-word in, curr-word
+ 736   tmp <- parse-decimal-int-from-slice curr-word
+ 737   var height/ebx: int <- copy tmp
+ 738   next-word in, curr-word
+ 739   # check color levels
+ 740   {
+ 741     tmp <- parse-decimal-int-from-slice curr-word
+ 742     compare tmp, 0xff
+ 743     break-if-=
+ 744     abort "initialize-image-from-ppm: supports exactly 255 levels per rgb channel"
+ 745   }
+ 746   var dest/edi: (addr int) <- get self, max
+ 747   copy-to *dest, tmp
+ 748   # save width, height
+ 749   dest <- get self, width
+ 750   copy-to *dest, width
+ 751   dest <- get self, height
+ 752   copy-to *dest, height
+ 753   # initialize data
+ 754   var capacity/edx: int <- copy width
+ 755   capacity <- multiply height
+ 756   # . multiply by 3 for the r/g/b channels
+ 757   var tmp/eax: int <- copy capacity
+ 758   tmp <- shift-left 1
+ 759   capacity <- add tmp
+ 760   #
+ 761   var data-ah/edi: (addr handle array byte) <- get self, data
+ 762   populate data-ah, capacity
+ 763   var _data/eax: (addr array byte) <- lookup *data-ah
+ 764   var data/edi: (addr array byte) <- copy _data
+ 765   var i/ebx: int <- copy 0
+ 766   {
+ 767     compare i, capacity
+ 768     break-if->=
+ 769     next-word in, curr-word
+ 770     var src/eax: int <- parse-decimal-int-from-slice curr-word
+ 771     {
+ 772       var dest/ecx: (addr byte) <- index data, i
+ 773       copy-byte-to *dest, src
+ 774     }
+ 775     i <- increment
+ 776     loop
+ 777   }
+ 778 }
+ 779 
+ 780 # import a color ascii "pixmap" (each pixel consists of 3 shades of r/g/b from 0 to 255)
+ 781 fn render-ppm-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
+ 782   var img/esi: (addr image) <- copy _img
+ 783   # yratio = height/img->height
+ 784   var img-height-a/eax: (addr int) <- get img, height
+ 785   var img-height/xmm0: float <- convert *img-height-a
+ 786   var yratio/xmm1: float <- convert height
+ 787   yratio <- divide img-height
+ 788   # xratio = width/img->width
+ 789   var img-width-a/eax: (addr int) <- get img, width
+ 790   var img-width/ebx: int <- copy *img-width-a
+ 791   var img-width-f/xmm0: float <- convert img-width
+ 792   var xratio/xmm2: float <- convert width
+ 793   xratio <- divide img-width-f
+ 794   # esi = img->data
+ 795   var img-data-ah/eax: (addr handle array byte) <- get img, data
+ 796   var _img-data/eax: (addr array byte) <- lookup *img-data-ah
+ 797   var img-data/esi: (addr array byte) <- copy _img-data
+ 798   var len/edi: int <- length img-data
+ 799   #
+ 800   var one/eax: int <- copy 1
+ 801   var one-f/xmm3: float <- convert one
+ 802   var width-f/xmm4: float <- convert width
+ 803   var height-f/xmm5: float <- convert height
+ 804   var zero/eax: int <- copy 0
+ 805   var zero-f/xmm0: float <- convert zero
+ 806   var y/xmm6: float <- copy zero-f
+ 807   {
+ 808     compare y, height-f
+ 809     break-if-float>=
+ 810     var imgy-f/xmm5: float <- copy y
+ 811     imgy-f <- divide yratio
+ 812     var imgy/edx: int <- truncate imgy-f
+ 813     var x/xmm7: float <- copy zero-f
+ 814     {
+ 815       compare x, width-f
+ 816       break-if-float>=
+ 817       var imgx-f/xmm5: float <- copy x
+ 818       imgx-f <- divide xratio
+ 819       var imgx/ecx: int <- truncate imgx-f
+ 820       var idx/eax: int <- copy imgy
+ 821       idx <- multiply img-width
+ 822       idx <- add imgx
+ 823       # . multiply by 3 for the r/g/b channels
+ 824       {
+ 825         var tmp/ecx: int <- copy idx
+ 826         tmp <- shift-left 1
+ 827         idx <- add tmp
+ 828       }
+ 829       # error info in case we rounded wrong and 'index' will fail bounds-check
+ 830       compare idx, len
+ 831       {
+ 832         break-if-<
+ 833         set-cursor-position 0/screen, 0x20/x 0x20/y
+ 834         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg
+ 835         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg
+ 836         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg
+ 837       }
+ 838       # r channel
+ 839       var r: int
+ 840       {
+ 841         var src-a/eax: (addr byte) <- index img-data, idx
+ 842         var src/eax: byte <- copy-byte *src-a
+ 843         copy-to r, src
+ 844       }
+ 845       idx <- increment
+ 846       # g channel
+ 847       var g: int
+ 848       {
+ 849         var src-a/eax: (addr byte) <- index img-data, idx
+ 850         var src/eax: byte <- copy-byte *src-a
+ 851         copy-to g, src
+ 852       }
+ 853       idx <- increment
+ 854       # b channel
+ 855       var b: int
+ 856       {
+ 857         var src-a/eax: (addr byte) <- index img-data, idx
+ 858         var src/eax: byte <- copy-byte *src-a
+ 859         copy-to b, src
+ 860       }
+ 861       idx <- increment
+ 862       # plot nearest color
+ 863       var color/eax: int <- nearest-color-euclidean r, g, b
+ 864       var screenx/ecx: int <- convert x
+ 865       screenx <- add xmin
+ 866       var screeny/edx: int <- convert y
+ 867       screeny <- add ymin
+ 868       pixel screen, screenx, screeny, color
+ 869       x <- add one-f
+ 870       loop
+ 871     }
+ 872     y <- add one-f
+ 873     loop
+ 874   }
+ 875 }
+ 876 
+ 877 fn dither-ppm-unordered _src: (addr image), _dest: (addr image) {
+ 878   var src/esi: (addr image) <- copy _src
+ 879   var dest/edi: (addr image) <- copy _dest
+ 880   # copy 'width'
+ 881   var src-width-a/eax: (addr int) <- get src, width
+ 882   var tmp/eax: int <- copy *src-width-a
+ 883   var src-width: int
+ 884   copy-to src-width, tmp
+ 885   {
+ 886     var dest-width-a/edx: (addr int) <- get dest, width
+ 887     copy-to *dest-width-a, tmp
+ 888   }
+ 889   # copy 'height'
+ 890   var src-height-a/eax: (addr int) <- get src, height
+ 891   var tmp/eax: int <- copy *src-height-a
+ 892   var src-height: int
+ 893   copy-to src-height, tmp
+ 894   {
+ 895     var dest-height-a/ecx: (addr int) <- get dest, height
+ 896     copy-to *dest-height-a, tmp
+ 897   }
+ 898   # compute scaling factor 255/max
+ 899   var target-scale/eax: int <- copy 0xff
+ 900   var scale-f/xmm7: float <- convert target-scale
+ 901   var src-max-a/eax: (addr int) <- get src, max
+ 902   var tmp-f/xmm0: float <- convert *src-max-a
+ 903   scale-f <- divide tmp-f
+ 904   # allocate 'data'
+ 905   var capacity/ebx: int <- copy src-width
+ 906   capacity <- multiply src-height
+ 907   var dest/edi: (addr image) <- copy _dest
+ 908   var dest-data-ah/eax: (addr handle array byte) <- get dest, data
+ 909   populate dest-data-ah, capacity
+ 910   var _dest-data/eax: (addr array byte) <- lookup *dest-data-ah
+ 911   var dest-data/edi: (addr array byte) <- copy _dest-data
+ 912   # error buffers per r/g/b channel
+ 913   var red-errors-storage: (array int 0xc0000)
+ 914   var tmp/eax: (addr array int) <- address red-errors-storage
+ 915   var red-errors: (addr array int)
+ 916   copy-to red-errors, tmp
+ 917   var green-errors-storage: (array int 0xc0000)
+ 918   var tmp/eax: (addr array int) <- address green-errors-storage
+ 919   var green-errors: (addr array int)
+ 920   copy-to green-errors, tmp
+ 921   var blue-errors-storage: (array int 0xc0000)
+ 922   var tmp/eax: (addr array int) <- address blue-errors-storage
+ 923   var blue-errors: (addr array int)
+ 924   copy-to blue-errors, tmp
+ 925   # transform 'data'
+ 926   var src-data-ah/eax: (addr handle array byte) <- get src, data
+ 927   var _src-data/eax: (addr array byte) <- lookup *src-data-ah
+ 928   var src-data/esi: (addr array byte) <- copy _src-data
+ 929   var y/edx: int <- copy 0
+ 930   {
+ 931     compare y, src-height
+ 932     break-if->=
+ 933     var x/ecx: int <- copy 0
+ 934     {
+ 935       compare x, src-width
+ 936       break-if->=
+ 937       # - update errors and compute color levels for current pixel in each channel
+ 938       # update red-error with current image pixel
+ 939       var red-error: int
+ 940       {
+ 941         var tmp/esi: int <- _read-dithering-error red-errors, x, y, src-width
+ 942         copy-to red-error, tmp
+ 943       }
+ 944       {
+ 945         var tmp/eax: int <- _ppm-error src-data, x, y, src-width, 0/red, scale-f
+ 946         add-to red-error, tmp
+ 947       }
+ 948       # recompute red channel for current pixel
+ 949       var red-level: int
+ 950       {
+ 951         var tmp/eax: int <- _error-to-ppm-channel red-error
+ 952         copy-to red-level, tmp
+ 953       }
+ 954       # update green-error with current image pixel
+ 955       var green-error: int
+ 956       {
+ 957         var tmp/esi: int <- _read-dithering-error green-errors, x, y, src-width
+ 958         copy-to green-error, tmp
+ 959       }
+ 960       {
+ 961         var tmp/eax: int <- _ppm-error src-data, x, y, src-width, 1/green, scale-f
+ 962         add-to green-error, tmp
+ 963       }
+ 964       # recompute green channel for current pixel
+ 965       var green-level: int
+ 966       {
+ 967         var tmp/eax: int <- _error-to-ppm-channel green-error
+ 968         copy-to green-level, tmp
+ 969       }
+ 970       # update blue-error with current image pixel
+ 971       var blue-error: int
+ 972       {
+ 973         var tmp/esi: int <- _read-dithering-error blue-errors, x, y, src-width
+ 974         copy-to blue-error, tmp
+ 975       }
+ 976       {
+ 977         var tmp/eax: int <- _ppm-error src-data, x, y, src-width, 2/blue, scale-f
+ 978         add-to blue-error, tmp
+ 979       }
+ 980       # recompute blue channel for current pixel
+ 981       var blue-level: int
+ 982       {
+ 983         var tmp/eax: int <- _error-to-ppm-channel blue-error
+ 984         copy-to blue-level, tmp
+ 985       }
+ 986       # - figure out the nearest color
+ 987 #?       {
+ 988 #?         compare red-level, 0x80
+ 989 #?         break-if->
+ 990 #?         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, red-level, 4/fg 0/bg
+ 991 #?         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, green-level, 2/fg 0/bg
+ 992 #?         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, blue-level, 9/fg 0/bg
+ 993 #?       }
+ 994       var nearest-color-index/eax: int <- nearest-color-euclidean red-level, green-level, blue-level
+ 995       {
+ 996         var nearest-color-index-byte/eax: byte <- copy-byte nearest-color-index
+ 997         _write-raw-buffer dest-data, x, y, src-width, nearest-color-index-byte
+ 998       }
+ 999       # - diffuse errors
+1000       var red-level: int
+1001       var green-level: int
+1002       var blue-level: int
+1003       {
+1004         var tmp-red-level/ecx: int <- copy 0
+1005         var tmp-green-level/edx: int <- copy 0
+1006         var tmp-blue-level/ebx: int <- copy 0
+1007         tmp-red-level, tmp-green-level, tmp-blue-level <- color-rgb nearest-color-index
+1008         copy-to red-level, tmp-red-level
+1009         copy-to green-level, tmp-green-level
+1010         copy-to blue-level, tmp-blue-level
+1011       }
+1012       # update red-error
+1013       var red-level-error/eax: int <- copy red-level
+1014       red-level-error <- shift-left 0x10
+1015       subtract-from red-error, red-level-error
+1016       _diffuse-dithering-error-floyd-steinberg red-errors, x, y, src-width, src-height, red-error
+1017       # update green-error
+1018       var green-level-error/eax: int <- copy green-level
+1019       green-level-error <- shift-left 0x10
+1020       subtract-from green-error, green-level-error
+1021       _diffuse-dithering-error-floyd-steinberg green-errors, x, y, src-width, src-height, green-error
+1022       # update blue-error
+1023       var blue-level-error/eax: int <- copy blue-level
+1024       blue-level-error <- shift-left 0x10
+1025       subtract-from blue-error, blue-level-error
+1026       _diffuse-dithering-error-floyd-steinberg blue-errors, x, y, src-width, src-height, blue-error
+1027       #
+1028       x <- increment
+1029       loop
+1030     }
+1031     y <- increment
+1032     loop
+1033   }
+1034 }
+1035 
+1036 # convert a single channel for a single image pixel to error space
+1037 fn _ppm-error buf: (addr array byte), x: int, y: int, width: int, channel: int, _scale-f: float -> _/eax: int {
+1038   # current image pixel
+1039   var initial-level/eax: byte <- _read-ppm-buffer buf, x, y, width, channel
+1040   # scale to 255 levels
+1041   var initial-level-int/eax: int <- copy initial-level
+1042   var initial-level-f/xmm0: float <- convert initial-level-int
+1043   var scale-f/xmm1: float <- copy _scale-f
+1044   initial-level-f <- multiply scale-f
+1045   initial-level-int <- convert initial-level-f
+1046   # switch to fixed-point with 16 bits of precision
+1047   initial-level-int <- shift-left 0x10
+1048   return initial-level-int
+1049 }
+1050 
+1051 fn _error-to-ppm-channel error: int -> _/eax: int {
+1052   # clamp(error >> 16)
+1053   var result/esi: int <- copy error
+1054   result <- shift-right-signed 0x10
+1055   {
+1056     compare result, 0
+1057     break-if->=
+1058     result <- copy 0
+1059   }
+1060   {
+1061     compare result, 0xff
+1062     break-if-<=
+1063     result <- copy 0xff
+1064   }
+1065   return result
+1066 }
+1067 
+1068 # read from a buffer containing alternating bytes from r/g/b channels
+1069 fn _read-ppm-buffer _buf: (addr array byte), x: int, y: int, width: int, channel: int -> _/eax: byte {
+1070   var buf/esi: (addr array byte) <- copy _buf
+1071   var idx/ecx: int <- copy y
+1072   idx <- multiply width
+1073   idx <- add x
+1074   var byte-idx/edx: int <- copy 3
+1075   byte-idx <- multiply idx
+1076   byte-idx <- add channel
+1077   var result-a/eax: (addr byte) <- index buf, byte-idx
+1078   var result/eax: byte <- copy-byte *result-a
+1079   return result
+1080 }
+1081 
+1082 # each byte in the image data is a color of the current palette
+1083 fn render-raw-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
+1084   var img/esi: (addr image) <- copy _img
+1085   # yratio = height/img->height
+1086   var img-height-a/eax: (addr int) <- get img, height
+1087   var img-height/xmm0: float <- convert *img-height-a
+1088   var yratio/xmm1: float <- convert height
+1089   yratio <- divide img-height
+1090   # xratio = width/img->width
+1091   var img-width-a/eax: (addr int) <- get img, width
+1092   var img-width/ebx: int <- copy *img-width-a
+1093   var img-width-f/xmm0: float <- convert img-width
+1094   var xratio/xmm2: float <- convert width
+1095   xratio <- divide img-width-f
+1096   # esi = img->data
+1097   var img-data-ah/eax: (addr handle array byte) <- get img, data
+1098   var _img-data/eax: (addr array byte) <- lookup *img-data-ah
+1099   var img-data/esi: (addr array byte) <- copy _img-data
+1100   var len/edi: int <- length img-data
+1101   #
+1102   var one/eax: int <- copy 1
+1103   var one-f/xmm3: float <- convert one
+1104   var width-f/xmm4: float <- convert width
+1105   var height-f/xmm5: float <- convert height
+1106   var zero/eax: int <- copy 0
+1107   var zero-f/xmm0: float <- convert zero
+1108   var y/xmm6: float <- copy zero-f
+1109   {
+1110     compare y, height-f
+1111     break-if-float>=
+1112     var imgy-f/xmm5: float <- copy y
+1113     imgy-f <- divide yratio
+1114     var imgy/edx: int <- truncate imgy-f
+1115     var x/xmm7: float <- copy zero-f
+1116     {
+1117       compare x, width-f
+1118       break-if-float>=
+1119       var imgx-f/xmm5: float <- copy x
+1120       imgx-f <- divide xratio
+1121       var imgx/ecx: int <- truncate imgx-f
+1122       var idx/eax: int <- copy imgy
+1123       idx <- multiply img-width
+1124       idx <- add imgx
+1125       # error info in case we rounded wrong and 'index' will fail bounds-check
+1126       compare idx, len
+1127       {
+1128         break-if-<
+1129         set-cursor-position 0/screen, 0x20/x 0x20/y
+1130         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg
+1131         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg
+1132         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg
+1133       }
+1134       var color-a/eax: (addr byte) <- index img-data, idx
+1135       var color/eax: byte <- copy-byte *color-a
+1136       var color-int/eax: int <- copy color
+1137       var screenx/ecx: int <- convert x
+1138       screenx <- add xmin
+1139       var screeny/edx: int <- convert y
+1140       screeny <- add ymin
+1141       pixel screen, screenx, screeny, color-int
+1142       x <- add one-f
+1143       loop
+1144     }
+1145     y <- add one-f
+1146     loop
+1147   }
+1148 }
+
+ + + -- cgit 1.4.1-2-gfad0