about summary refs log tree commit diff stats
path: root/apps/colors.mu
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-07-16 08:09:42 -0700
committerKartik K. Agaram <vc@akkartik.com>2021-07-16 08:28:56 -0700
commit44d26b77c45668c9b0c99894a4294cec004361fe (patch)
tree68a5dcd4971873efd4ce184e9bf9a531c2161813 /apps/colors.mu
parentac45f097153afd3a89f43886e4124c5b2c26b98a (diff)
downloadmu-44d26b77c45668c9b0c99894a4294cec004361fe.tar.gz
.
Diffstat (limited to 'apps/colors.mu')
-rw-r--r--apps/colors.mu242
1 files changed, 242 insertions, 0 deletions
diff --git a/apps/colors.mu b/apps/colors.mu
new file mode 100644
index 00000000..78e58838
--- /dev/null
+++ b/apps/colors.mu
@@ -0,0 +1,242 @@
+# Return colors 'near' a given r/g/b value (expressed in hex)
+# If we did this rigorously we'd need to implement cosines. So we won't.
+#
+# To build:
+#   $ ./translate apps/colors.mu
+#
+# Example session:
+#   $ qemu-system-i386 code.img
+#   Enter 3 hex bytes for r, g, b (lowercase; no 0x prefix) separated by a single space> aa 0 aa
+#   5
+# This means only color 5 in the default palette is similar to #aa00aa.
+
+fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+  var in-storage: (stream byte 0x10)
+  var in/esi: (addr stream byte) <- address in-storage
+  {
+    # print prompt
+    var x/eax: int <- draw-text-rightward screen, "Enter 3 hex bytes for r, g, b (lowercase; no 0x prefix) separated by a single space> ", 0x10/x, 0x80/xmax, 0x28/y, 3/fg/cyan, 0/bg
+    # read line from keyboard
+    clear-stream in
+    {
+      draw-cursor screen, 0x20/space
+      var key/eax: byte <- read-key keyboard
+      compare key, 0xa/newline
+      break-if-=
+      compare key, 0
+      loop-if-=
+      var key2/eax: int <- copy key
+      append-byte in, key2
+      var g/eax: grapheme <- copy key2
+      draw-grapheme-at-cursor screen, g, 0xf/fg, 0/bg
+      move-cursor-right 0
+      loop
+    }
+    clear-screen screen
+    # parse
+    var a/ecx: int <- copy 0
+    var b/edx: int <- copy 0
+    var c/ebx: int <- copy 0
+    # a, b, c = r, g, b
+    a, b, c <- parse in
+#?     set-cursor-position screen, 0x10/x, 0x1a/y
+#?     draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, a, 7/fg, 0/bg
+#?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+#?     draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, b, 7/fg, 0/bg
+#?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+#?     draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, c, 7/fg, 0/bg
+    a, b, c <- hsl a, b, c
+    # return all colors in the same quadrant in h, s and l
+    print-nearby-colors screen, a, b, c
+    # another metric
+    var color/eax: int <- nearest-color-euclidean-hsl a, b, c
+    set-cursor-position screen, 0x10/x, 0x26/y
+    draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "nearest (euclidean, h/s/l): ", 0xf/fg, 0/bg
+    draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, color, 7/fg, 0/bg
+    draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 0xf/fg, 0/bg
+    draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "               ", 0/fg, color
+    #
+    loop
+  }
+}
+
+# read exactly 3 words in a single line
+# Each word consists of exactly 1 or 2 hex bytes. No hex prefix.
+fn parse in: (addr stream byte) -> _/ecx: int, _/edx: int, _/ebx: int {
+  # read first byte of r
+  var tmp/eax: byte <- read-byte in
+  {
+    var valid?/eax: boolean <- hex-digit? tmp
+    compare valid?, 0/false
+    break-if-!=
+    abort "invalid byte 0 of r"
+  }
+  tmp <- fast-hex-digit-value tmp
+  var r/ecx: int <- copy tmp
+#?   set-cursor-position 0/screen, 0x10/x, 0x10/y
+#?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, r, 7/fg, 0/bg
+  # read second byte of r
+  tmp <- read-byte in
+  {
+    {
+      var valid?/eax: boolean <- hex-digit? tmp
+      compare valid?, 0/false
+    }
+    break-if-=
+    r <- shift-left 4
+    tmp <- fast-hex-digit-value tmp
+#?     {
+#?       var foo/eax: int <- copy tmp
+#?       set-cursor-position 0/screen, 0x10/x, 0x11/y
+#?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg, 0/bg
+#?     }
+    r <- add tmp
+#?     {
+#?       set-cursor-position 0/screen, 0x10/x, 0x12/y
+#?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, r, 7/fg, 0/bg
+#?     }
+    tmp <- read-byte in  # skip space
+  }
+  # read first byte of g
+  var tmp/eax: byte <- read-byte in
+  {
+    var valid?/eax: boolean <- hex-digit? tmp
+    compare valid?, 0/false
+    break-if-!=
+    abort "invalid byte 0 of g"
+  }
+  tmp <- fast-hex-digit-value tmp
+  var g/edx: int <- copy tmp
+#?   set-cursor-position 0/screen, 0x10/x, 0x13/y
+#?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, g, 7/fg, 0/bg
+  # read second byte of g
+  tmp <- read-byte in
+  {
+    {
+      var valid?/eax: boolean <- hex-digit? tmp
+      compare valid?, 0/false
+    }
+    break-if-=
+    g <- shift-left 4
+    tmp <- fast-hex-digit-value tmp
+#?     {
+#?       var foo/eax: int <- copy tmp
+#?       set-cursor-position 0/screen, 0x10/x, 0x14/y
+#?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg, 0/bg
+#?     }
+    g <- add tmp
+#?     {
+#?       set-cursor-position 0/screen, 0x10/x, 0x15/y
+#?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, g, 7/fg, 0/bg
+#?     }
+    tmp <- read-byte in  # skip space
+  }
+  # read first byte of b
+  var tmp/eax: byte <- read-byte in
+  {
+    var valid?/eax: boolean <- hex-digit? tmp
+    compare valid?, 0/false
+    break-if-!=
+    abort "invalid byte 0 of b"
+  }
+  tmp <- fast-hex-digit-value tmp
+  var b/ebx: int <- copy tmp
+#?   set-cursor-position 0/screen, 0x10/x, 0x16/y
+#?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, b, 7/fg, 0/bg
+  # read second byte of b
+  {
+    {
+      var done?/eax: boolean <- stream-empty? in
+      compare done?, 0/false
+    }
+    break-if-!=
+    tmp <- read-byte in
+    {
+      var valid?/eax: boolean <- hex-digit? tmp
+      compare valid?, 0/false
+    }
+    break-if-=
+    b <- shift-left 4
+    tmp <- fast-hex-digit-value tmp
+#?     {
+#?       var foo/eax: int <- copy tmp
+#?       set-cursor-position 0/screen, 0x10/x, 0x17/y
+#?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg, 0/bg
+#?     }
+    b <- add tmp
+#?     {
+#?       set-cursor-position 0/screen, 0x10/x, 0x18/y
+#?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, b, 7/fg, 0/bg
+#?     }
+  }
+  return r, g, b
+}
+
+# no error checking
+fn fast-hex-digit-value in: byte -> _/eax: byte {
+  var result/eax: byte <- copy in
+  compare result, 0x39
+  {
+    break-if->
+    result <- subtract 0x30/0
+    return result
+  }
+  result <- subtract 0x61/a
+  result <- add 0xa/10
+  return result
+}
+
+fn print-nearby-colors screen: (addr screen), h: int, s: int, l: int {
+#?   set-cursor-position screen, 0x10/x, 0x1c/y
+#?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, h, 7/fg, 0/bg
+#?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+#?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, s, 7/fg, 0/bg
+#?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+#?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, l, 7/fg, 0/bg
+  # save just top 2 bits of each, so that we narrow down to 1/64th of the volume
+  shift-right h, 6
+  shift-right s, 6
+  shift-right l, 6
+#?   set-cursor-position screen, 0x10/x, 0x1/y
+#?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, h, 7/fg, 0/bg
+#?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+#?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, s, 7/fg, 0/bg
+#?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+#?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, l, 7/fg, 0/bg
+  var a/ecx: int <- copy 0
+  var b/edx: int <- copy 0
+  var c/ebx: int <- copy 0
+  var color/eax: int <- copy 0
+  var y/esi: int <- copy 2
+  {
+    compare color, 0x100
+    break-if->=
+    a, b, c <- color-rgb color
+    a, b, c <- hsl a, b, c
+    a <- shift-right 6
+    b <- shift-right 6
+    c <- shift-right 6
+    {
+      compare a, h
+      break-if-!=
+      compare b, s
+      break-if-!=
+      compare c, l
+      break-if-!=
+      set-cursor-position screen, 0x10/x, y
+      draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, color, 7/fg, 0/bg
+      set-cursor-position screen, 0x14/x, y
+      draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+      draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "               ", 0/fg, color
+#?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+#?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, a, 7/fg, 0/bg
+#?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+#?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, b, 7/fg, 0/bg
+#?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+#?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, c, 7/fg, 0/bg
+      y <- increment
+    }
+    color <- increment
+    loop
+  }
+}