https://github.com/akkartik/mu/blob/main/img.mu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 type image {
16 type: int
17
18
19
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
35 var s-storage: (stream byte 0x200000)
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
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
127
128
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
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
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
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
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
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
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
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
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
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
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
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
263 dest <- get self, width
264 copy-to *dest, width
265 dest <- get self, height
266 copy-to *dest, height
267
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
489 {
490 var tmp/eax: int <- copy initial-color-int
491 tmp <- shift-left 0x10
492 error <- add tmp
493 }
494
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
508 nearest-color <- and 0xf0
509
510 {
511 var tmp/eax: int <- copy nearest-color
512 tmp <- shift-left 0x10
513 error <- subtract tmp
514 }
515
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
531
532
533
534
535
536
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
548
549 var delta/ecx: int <- copy error
550 delta <- shift-right-signed 4
551
552
553
554
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
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
619
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
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
694
695
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
704
705
706
707
708
709
710
711
712 {
713 compare x, 0x20
714 break-if->=
715 return
716 }
717
718
719
720
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
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
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
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
749 dest <- get self, width
750 copy-to *dest, width
751 dest <- get self, height
752 copy-to *dest, height
753
754 var capacity/edx: int <- copy width
755 capacity <- multiply height
756
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
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
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
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
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
824 {
825 var tmp/ecx: int <- copy idx
826 tmp <- shift-left 1
827 idx <- add tmp
828 }
829
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
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
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
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
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
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
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
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
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
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
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
938
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
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
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
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
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
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
987
988
989
990
991
992
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
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
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
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
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
1037 fn _ppm-error buf: (addr array byte), x: int, y: int, width: int, channel: int, _scale-f: float -> _/eax: int {
1038
1039 var initial-level/eax: byte <- _read-ppm-buffer buf, x, y, width, channel
1040
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
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
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
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
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
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
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
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
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 }