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