https://github.com/akkartik/mu/blob/main/colors.mu

      1 # Return colors 'near' a given r/g/b value (expressed in hex)
      2 # If we did this rigorously we'd need to implement cosines. So we won't.
      3 #
      4 # To build:
      5 #   $ ./translate colors.mu
      6 #
      7 # Example session:
      8 #   $ qemu-system-i386 code.img
      9 #   Enter 3 hex bytes for r, g, b (lowercase; no 0x prefix) separated by a single space> aa 0 aa
     10 #   5
     11 # This means only color 5 in the default palette is similar to #aa00aa.
     12
     13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
     14   var in-storage: (stream byte 0x10)
     15   var in/esi: (addr stream byte) <- address in-storage
     16   {
     17     # print prompt
     18     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
     19     # read line from keyboard
     20     clear-stream in
     21     {
     22       draw-cursor screen, 0x20/space
     23       var key/eax: byte <- read-key keyboard
     24       compare key, 0xa/newline
     25       break-if-=
     26       compare key, 0
     27       loop-if-=
     28       var key2/eax: int <- copy key
     29       append-byte in, key2
     30       var g/eax: grapheme <- copy key2
     31       draw-grapheme-at-cursor screen, g, 0xf/fg, 0/bg
     32       move-cursor-right 0
     33       loop
     34     }
     35     clear-screen screen
     36     # parse
     37     var a/ecx: int <- copy 0
     38     var b/edx: int <- copy 0
     39     var c/ebx: int <- copy 0
     40     # a, b, c = r, g, b
     41     a, b, c <- parse in
     42 #?     set-cursor-position screen, 0x10/x, 0x1a/y
     43 #?     draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, a, 7/fg, 0/bg
     44 #?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
     45 #?     draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, b, 7/fg, 0/bg
     46 #?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
     47 #?     draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, c, 7/fg, 0/bg
     48     a, b, c <- hsl a, b, c
     49     # return all colors in the same quadrant in h, s and l
     50     print-nearby-colors screen, a, b, c
     51     #
     52     loop
     53   }
     54 }
     55
     56 # read exactly 3 words in a single line
     57 # Each word consists of exactly 1 or 2 hex bytes. No hex prefix.
     58 fn parse in: (addr stream byte) -> _/ecx: int, _/edx: int, _/ebx: int {
     59   # read first byte of r
     60   var tmp/eax: byte <- read-byte in
     61   {
     62     var valid?/eax: boolean <- hex-digit? tmp
     63     compare valid?, 0/false
     64     break-if-!=
     65     abort "invalid byte 0 of r"
     66   }
     67   tmp <- fast-hex-digit-value tmp
     68   var r/ecx: int <- copy tmp
     69 #?   set-cursor-position 0/screen, 0x10/x, 0x10/y
     70 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, r, 7/fg, 0/bg
     71   # read second byte of r
     72   tmp <- read-byte in
     73   {
     74     {
     75       var valid?/eax: boolean <- hex-digit? tmp
     76       compare valid?, 0/false
     77     }
     78     break-if-=
     79     r <- shift-left 4
     80     tmp <- fast-hex-digit-value tmp
     81 #?     {
     82 #?       var foo/eax: int <- copy tmp
     83 #?       set-cursor-position 0/screen, 0x10/x, 0x11/y
     84 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg, 0/bg
     85 #?     }
     86     r <- add tmp
     87 #?     {
     88 #?       set-cursor-position 0/screen, 0x10/x, 0x12/y
     89 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, r, 7/fg, 0/bg
     90 #?     }
     91     tmp <- read-byte in  # skip space
     92   }
     93   # read first byte of g
     94   var tmp/eax: byte <- read-byte in
     95   {
     96     var valid?/eax: boolean <- hex-digit? tmp
     97     compare valid?, 0/false
     98     break-if-!=
     99     abort "invalid byte 0 of g"
    100   }
    101   tmp <- fast-hex-digit-value tmp
    102   var g/edx: int <- copy tmp
    103 #?   set-cursor-position 0/screen, 0x10/x, 0x13/y
    104 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, g, 7/fg, 0/bg
    105   # read second byte of g
    106   tmp <- read-byte in
    107   {
    108     {
    109       var valid?/eax: boolean <- hex-digit? tmp
    110       compare valid?, 0/false
    111     }
    112     break-if-=
    113     g <- shift-left 4
    114     tmp <- fast-hex-digit-value tmp
    115 #?     {
    116 #?       var foo/eax: int <- copy tmp
    117 #?       set-cursor-position 0/screen, 0x10/x, 0x14/y
    118 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg, 0/bg
    119 #?     }
    120     g <- add tmp
    121 #?     {
    122 #?       set-cursor-position 0/screen, 0x10/x, 0x15/y
    123 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, g, 7/fg, 0/bg
    124 #?     }
    125     tmp <- read-byte in  # skip space
    126   }
    127   # read first byte of b
    128   var tmp/eax: byte <- read-byte in
    129   {
    130     var valid?/eax: boolean <- hex-digit? tmp
    131     compare valid?, 0/false
    132     break-if-!=
    133     abort "invalid byte 0 of b"
    134   }
    135   tmp <- fast-hex-digit-value tmp
    136   var b/ebx: int <- copy tmp
    137 #?   set-cursor-position 0/screen, 0x10/x, 0x16/y
    138 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, b, 7/fg, 0/bg
    139   # read second byte of b
    140   {
    141     {
    142       var done?/eax: boolean <- stream-empty? in
    143       compare done?, 0/false
    144     }
    145     break-if-!=
    146     tmp <- read-byte in
    147     {
    148       var valid?/eax: boolean <- hex-digit? tmp
    149       compare valid?, 0/false
    150     }
    151     break-if-=
    152     b <- shift-left 4
    153     tmp <- fast-hex-digit-value tmp
    154 #?     {
    155 #?       var foo/eax: int <- copy tmp
    156 #?       set-cursor-position 0/screen, 0x10/x, 0x17/y
    157 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg, 0/bg
    158 #?     }
    159     b <- add tmp
    160 #?     {
    161 #?       set-cursor-position 0/screen, 0x10/x, 0x18/y
    162 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, b, 7/fg, 0/bg
    163 #?     }
    164   }
    165   return r, g, b
    166 }
    167
    168 # no error checking
    169 fn fast-hex-digit-value in: byte -> _/eax: byte {
    170   var result/eax: byte <- copy in
    171   compare result, 0x39
    172   {
    173     break-if->
    174     result <- subtract 0x30/0
    175     return result
    176   }
    177   result <- subtract 0x61/a
    178   result <- add 0xa/10
    179   return result
    180 }
    181
    182 fn print-nearby-colors screen: (addr screen), h: int, s: int, l: int {
    183 #?   set-cursor-position screen, 0x10/x, 0x1c/y
    184 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, h, 7/fg, 0/bg
    185 #?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
    186 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, s, 7/fg, 0/bg
    187 #?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
    188 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, l, 7/fg, 0/bg
    189   # save just top 2 bits of each, so that we narrow down to 1/64th of the volume
    190   shift-right h, 6
    191   shift-right s, 6
    192   shift-right l, 6
    193 #?   set-cursor-position screen, 0x10/x, 0x1/y
    194 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, h, 7/fg, 0/bg
    195 #?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
    196 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, s, 7/fg, 0/bg
    197 #?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
    198 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, l, 7/fg, 0/bg
    199   var a/ecx: int <- copy 0
    200   var b/edx: int <- copy 0
    201   var c/ebx: int <- copy 0
    202   var color/eax: int <- copy 0
    203   var y/esi: int <- copy 2
    204   {
    205     compare color, 0x100
    206     break-if->=
    207     a, b, c <- color-rgb color
    208     a, b, c <- hsl a, b, c
    209     a <- shift-right 6
    210     b <- shift-right 6
    211     c <- shift-right 6
    212     {
    213       compare a, h
    214       break-if-!=
    215       compare b, s
    216       break-if-!=
    217       compare c, l
    218       break-if-!=
    219       set-cursor-position screen, 0x10/x, y
    220       draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, color, 7/fg, 0/bg
    221       set-cursor-position screen, 0x14/x, y
    222       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
    223       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "               ", 0/fg, color
    224 #?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
    225 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, a, 7/fg, 0/bg
    226 #?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
    227 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, b, 7/fg, 0/bg
    228 #?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
    229 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, c, 7/fg, 0/bg
    230       y <- increment
    231     }
    232     color <- increment
    233     loop
    234   }
    235 }