# Loading images from disk, rendering images to screen. # # Currently supports ASCII Netpbm formats. # https://en.wikipedia.org/wiki/Netpbm#File_formats type image { type: int # supported types: # 1: portable bitmap (P1) - pixels 0 or 1 # 2: portable greymap (P2) - pixels 1-byte greyscale values # 3: portable pixmap (P3) - pixels 3-byte rgb values max: int width: int height: int data: (handle array byte) } fn initialize-image _self: (addr image), in: (addr stream byte) { var self/esi: (addr image) <- copy _self var mode-storage: slice var mode/ecx: (addr slice) <- address mode-storage next-word-skipping-comments in, mode { var P1?/eax: boolean <- slice-equal? mode, "P1" compare P1?, 0/false break-if-= var type-a/eax: (addr int) <- get self, type copy-to *type-a, 1/ppm initialize-image-from-pbm self, in return } { var P2?/eax: boolean <- slice-equal? mode, "P2" compare P2?, 0/false break-if-= var type-a/eax: (addr int) <- get self, type copy-to *type-a, 2/pgm initialize-image-from-pgm self, in return } { var P3?/eax: boolean <- slice-equal? mode, "P3" compare P3?, 0/false break-if-= var type-a/eax: (addr int) <- get self, type copy-to *type-a, 3/ppm initialize-image-from-ppm self, in return } abort "initialize-image: unrecognized image type" } # dispatch to a few variants with mostly identical boilerplate # TODO: if we have more resolution we could actually use it to improve # dithering fn render-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int { var img/esi: (addr image) <- copy _img var type-a/eax: (addr int) <- get img, type { compare *type-a, 1/pbm break-if-!= render-pbm-image screen, img, xmin, ymin, width, height return } { compare *type-a, 2/pgm break-if-!= var img2-storage: image var img2/edi: (addr image) <- address img2-storage dither-pgm-unordered img, img2 render-raw-image screen, img2, xmin, ymin, width, height return } { compare *type-a, 3/ppm break-if-!= var img2-storage: image var img2/edi: (addr image) <- address img2-storage dither-ppm-unordered img, img2 render-raw-image screen, img2, xmin, ymin, width, height return } #? abort "render-image: unrecognized image type" } ## helpers # import a black-and-white ascii bitmap (each pixel is 0 or 1) fn initialize-image-from-pbm _self: (addr image), in: (addr stream byte) { var self/esi: (addr image) <- copy _self var curr-word-storage: slice var curr-word/ecx: (addr slice) <- address curr-word-storage # load width, height next-word-skipping-comments in, curr-word var tmp/eax: int <- parse-decimal-int-from-slice curr-word var width/edx: int <- copy tmp next-word-skipping-comments in, curr-word tmp <- parse-decimal-int-from-slice curr-word var height/ebx: int <- copy tmp # save width, height var dest/eax: (addr int) <- get self, width copy-to *dest, width dest <- get self, height copy-to *dest, height # initialize data var capacity/edx: int <- copy width capacity <- multiply height var data-ah/edi: (addr handle array byte) <- get self, data populate data-ah, capacity var _data/eax: (addr array byte) <- lookup *data-ah var data/edi: (addr array byte) <- copy _data var i/ebx: int <- copy 0 { compare i, capacity break-if->= next-word-skipping-comments in, curr-word var src/eax: int <- parse-decimal-int-from-slice curr-word { var dest/ecx: (addr byte) <- index data, i copy-byte-to *dest, src } i <- increment loop } } # render a black-and-white ascii bitmap (each pixel is 0 or 1) fn render-pbm-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int { var img/esi: (addr image) <- copy _img # yratio = height/img->height var img-height-a/eax: (addr int) <- get img, height var img-height/xmm0: float <- convert *img-height-a var yratio/xmm1: float <- convert height yratio <- divide img-height # xratio = width/img->width var img-width-a/eax: (addr int) <- get img, width var img-width/ebx: int <- copy *img-width-a var img-width-f/xmm0: float <- convert img-width var xratio/xmm2: float <- convert width xratio <- divide img-width-f # esi = img->data var img-data-ah/eax: (addr handle array byte) <- get img, data var _img-data/eax: (addr array byte) <- lookup *img-data-ah var img-data/esi: (addr array byte) <- copy _img-data var len/edi: int <- length img-data # var one/eax: int <- copy 1 var one-f/xmm3: float <- convert one var width-f/xmm4: float <- convert width var height-f/xmm5: float <- convert height var zero/eax: int <- copy 0 var zero-f/xmm0: float <- convert zero var y/xmm6: float <- copy zero-f { compare y, height-f break-if-float>= var imgy-f/xmm5: float <- copy y imgy-f <- divide yratio var imgy/edx: int <- truncate imgy-f var x/xmm7: float <- copy zero-f { compare x, width-f break-if-float>= var imgx-f/xmm5: float <- copy x imgx-f <- divide xratio var imgx/ecx: int <- truncate imgx-f var idx/eax: int <- copy imgy idx <- multiply img-width idx <- add imgx # error info in case we rounded wrong and 'index' will fail bounds-check compare idx, len { break-if-< set-cursor-position 0/screen, 0x20/x 0x20/y draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg } var src-a/eax: (addr byte) <- index img-data, idx var src/eax: byte <- copy-byte *src-a var color-int/eax: int <- copy src { compare color-int, 0/black break-if-= color-int <- copy 0xf/white } var screenx/ecx: int <- convert x screenx <- add xmin var screeny/edx: int <- convert y screeny <- add ymin pixel screen, screenx, screeny, color-int x <- add one-f loop } y <- add one-f loop } } # import a greyscale ascii "greymap" (each pixel is a shade of grey from 0 to 255) fn initialize-image-from-pgm _self: (addr image), in: (addr stream byte) { var self/esi: (addr image) <- copy _self var curr-word-storage: slice var curr-word/ecx: (addr slice) <- address curr-word-storage # load width, height next-word-skipping-comments in, curr-word var tmp/eax: int <- parse-decimal-int-from-slice curr-word var width/edx: int <- copy tmp next-word-skipping-comments in, curr-word tmp <- parse-decimal-int-from-slice curr-word var height/ebx: int <- copy tmp # check and save color levels next-word-skipping-comments in, curr-word { tmp <- parse-decimal-int-from-slice curr-word compare tmp, 0xff break-if-= 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 } var dest/edi: (addr int) <- get self, max copy-to *dest, tmp # save width, height dest <- get self, width copy-to *dest, width dest <- get self, height copy-to *dest, height # initialize data var capacity/edx: int <- copy width capacity <- multiply height var data-ah/edi: (addr handle array byte) <- get self, data populate data-ah, capacity var _data/eax: (addr array byte) <- lookup *data-ah var data/edi: (addr array byte) <- copy _data var i/ebx: int <- copy 0 { compare i, capacity break-if->= next-word-skipping-comments in, curr-word var src/eax: int <- parse-decimal-int-from-slice curr-word { var dest/ecx: (addr byte) <- index data, i copy-byte-to *dest, src } i <- increment loop } } # render a greyscale ascii "greymap" (each pixel is a shade of grey from 0 to 255) by quantizing the shades fn render-pgm-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int { var img/esi: (addr image) <- copy _img # yratio = height/img->height var img-height-a/eax: (addr int) <- get img, height var img-height/xmm0: float <- convert *img-height-a var yratio/xmm1: float <- convert height yratio <- divide img-height # xratio = width/img->width var img-width-a/eax: (addr int) <- get img, width var img-width/ebx: int <- copy *img-width-a var img-width-f/xmm0: float <- convert img-width var xratio/xmm2: float <- convert width xratio <- divide img-width-f # esi = img->data var img-data-ah/eax: (addr handle array byte) <- get img, data var _img-data/eax: (addr array byte) <- lookup *img-data-ah var img-data/esi: (addr array byte) <- copy _img-data var len/edi: int <- length img-data # var one/eax: int <- copy 1 var one-f/xmm3: float <- convert one var width-f/xmm4: float <- convert width var height-f/xmm5: float <- convert height var zero/eax: int <- copy 0 var zero-f/xmm0: float <- convert zero var y/xmm6: float <- copy zero-f { compare y, height-f break-if-float>= var imgy-f/xmm5: float <- copy y imgy-f <- divide yratio var imgy/edx: int <- truncate imgy-f var x/xmm7: float <- copy zero-f { compare x, width-f break-if-float>= var imgx-f/xmm5: float <- copy x imgx-f <- divide xratio var imgx/ecx: int <- truncate imgx-f var idx/eax: int <- copy imgy idx <- multiply img-width idx <- add imgx # error info in case we rounded wrong and 'index' will fail bounds-check compare idx, len { break-if-< set-cursor-position 0/screen, 0x20/x 0x20/y draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg } var src-a/eax: (addr byte) <- index img-data, idx var src/eax: byte <- copy-byte *src-a var color-int/eax: int <- nearest-grey src var screenx/ecx: int <- convert x screenx <- add xmin var screeny/edx: int <- convert y screeny <- add ymin pixel screen, screenx, screeny, color-int x <- add one-f loop } y <- add one-f loop } } fn nearest-grey level-255: byte -> _/eax: int { var result/eax: int <- copy level-255 result <- shift-right 4 result <- add 0x10 return result } fn dither-pgm-unordered-monochrome _src: (addr image), _dest: (addr image) { var src/esi: (addr image) <- copy _src var dest/edi: (addr image) <- copy _dest # copy 'width' var src-width-a/eax: (addr int) <- get src, width var tmp/eax: int <- copy *src-width-a var src-width: int copy-to src-width, tmp { var dest-width-a/edx: (addr int) <- get dest, width copy-to *dest-width-a, tmp } # copy 'height' var src-height-a/eax: (addr int) <- get src, height var tmp/eax: int <- copy *src-height-a var src-height: int copy-to src-height, tmp { var dest-height-a/ecx: (addr int) <- get dest, height copy-to *dest-height-a, tmp } # transform 'data' var capacity/ebx: int <- copy src-width capaci
[colours]
bkgnd=default
titlebar=white
titlebar.text=black
titlebar.brackets=black
titlebar.unencrypted=black
titlebar.encrypted=black
titlebar.untrusted=black
titlebar.trusted=black
titlebar.online=black
titlebar.offline=black
titlebar.away=black
titlebar.chat=black
titlebar.dnd=black
titlebar.xa=black
statusbar=white
statusbar.text=black
statusbar.brackets=black
statusbar.active=black
statusbar.new=black
main.text=white
main.text.me=white
main.text.them=white
main.splash=white
main.time=white
input.text=white
subscribed=white
unsubscribed=white
otr.started.trusted=white
otr.started.untrusted=white
otr.ended=white
otr.trusted=white
otr.untrusted=white
online=white
away=white
chat=white
dnd=white
xa=white
offline=white
incoming=white
typing=white
gone=white
error=white
roominfo=white
roommention=white
me=white
them=white
roster.header=white
occupants.header=white
receipt.sent=white