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

      1 # Hue/saturation/luminance for an rgb triple.
      2 # rgb are in [0, 256)
      3 # hsl are also returned in [0, 256)
      4 # from https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl
      5 fn hsl r: int, g: int, b: int -> _/ecx: int, _/edx: int, _/ebx: int {
      6   var _max/eax: int <- maximum r, g
      7   _max <- maximum _max, b
      8   var max/ecx: int <- copy _max
      9   var _min/eax: int <- minimum r, g
     10   _min <- minimum _min, b
     11   var min/edx: int <- copy _min
     12   var luminance/ebx: int <- copy min
     13   luminance <- add max
     14   luminance <- shift-right 1  # TODO: round up instead of down
     15   # if rgb are all equal, it's a shade of grey
     16   compare min, max
     17   {
     18     break-if-!=
     19     return 0, 0, luminance
     20   }
     21   # saturation =
     22   #   luminance < 128 | 255*(max-min)/         (max+min)
     23   #   otherwise       | 255*(max-min)/(2*255 - (max+min))
     24   var nr/esi: int <- copy max
     25   nr <- subtract min
     26   var dr/eax: int <- copy 0
     27   compare luminance, 0x80
     28   {
     29     break-if->=
     30     dr <- copy max
     31     dr <- add min
     32   }
     33   {
     34     break-if-<
     35     dr <- copy 0xff
     36     dr <- shift-left 1
     37     dr <- subtract max
     38     dr <- subtract min
     39   }
     40   var q/xmm0: float <- convert nr
     41   var tmp/xmm1: float <- convert dr
     42   q <- divide tmp
     43   var int-255/eax: int <- copy 0xff
     44   tmp <- convert int-255
     45   q <- multiply tmp
     46   var saturation/esi: int <- convert q
     47   # hue =
     48   #   red is max   | 256.0/6*       (g-b)/(max-min)
     49   #   green is max | 256.0/6*(2.0 + (b-r)/(max-min))
     50   #   blue is max  | 256.0/6*(4.0 + (r-g)/(max-min))
     51   var zero/eax: int <- copy 0
     52   var hue-f/xmm0: float <- convert zero
     53   var dr/eax: int <- copy max
     54   dr <- subtract min
     55   var dr-f/xmm1: float <- convert dr
     56   $hsl:compute-hue-normalized: {
     57     compare r, max
     58     {
     59       break-if-!=
     60       var nr/eax: int <- copy g
     61       nr <- subtract b
     62       hue-f <- convert nr
     63       hue-f <- divide dr-f
     64       break $hsl:compute-hue-normalized
     65     }
     66     compare g, max
     67     {
     68       break-if-!=
     69       var nr/eax: int <- copy b
     70       nr <- subtract r
     71       var f/xmm2: float <- convert nr
     72       f <- divide dr-f
     73       var two/ecx: int <- copy 2
     74       hue-f <- convert two
     75       hue-f <- add f
     76       break $hsl:compute-hue-normalized
     77     }
     78     compare b, max
     79     {
     80       break-if-!=
     81       var nr/eax: int <- copy r
     82       nr <- subtract g
     83       var f/xmm2: float <- convert nr
     84       f <- divide dr-f
     85       var two/ecx: int <- copy 4
     86       hue-f <- convert two
     87       hue-f <- add f
     88       break $hsl:compute-hue-normalized
     89     }
     90   }
     91   var int-256/eax: int <- copy 0x100
     92   var scaling-factor/xmm1: float <- convert int-256
     93   var int-6/eax: int <- copy 6
     94   var six-f/xmm2: float <- convert int-6
     95   scaling-factor <- divide six-f
     96   hue-f <- multiply scaling-factor
     97   var hue/eax: int <- convert hue-f
     98   # if hue < 0, hue = 256 - hue
     99   compare hue, 0
    100   {
    101     break-if->=
    102     var tmp/ecx: int <- copy 0x100
    103     tmp <- subtract hue
    104     hue <- copy tmp
    105   }
    106   return hue, saturation, luminance
    107 }
    108
    109 fn test-hsl-black {
    110   var h/ecx: int <- copy 0
    111   var s/edx: int <- copy 0
    112   var l/ebx: int <- copy 0
    113   h, s, l <- hsl 0, 0, 0
    114   check-ints-equal h, 0, "F - test-hsl-black/hue"
    115   check-ints-equal s, 0, "F - test-hsl-black/saturation"
    116   check-ints-equal l, 0, "F - test-hsl-black/luminance"
    117 }
    118
    119 fn test-hsl-white {
    120   var h/ecx: int <- copy 0
    121   var s/edx: int <- copy 0
    122   var l/ebx: int <- copy 0
    123   h, s, l <- hsl 0xff, 0xff, 0xff
    124   check-ints-equal h, 0, "F - test-hsl-white/hue"
    125   check-ints-equal s, 0, "F - test-hsl-white/saturation"
    126   check-ints-equal l, 0xff, "F - test-hsl-white/luminance"
    127 }
    128
    129 fn test-hsl-grey {
    130   var h/ecx: int <- copy 0
    131   var s/edx: int <- copy 0
    132   var l/ebx: int <- copy 0
    133   h, s, l <- hsl 0x30, 0x30, 0x30
    134   check-ints-equal h, 0, "F - test-hsl-grey/hue"
    135   check-ints-equal s, 0, "F - test-hsl-grey/saturation"
    136   check-ints-equal l, 0x30, "F - test-hsl-grey/luminance"
    137 }
    138
    139 # red hues: 0-0x54
    140 fn test-hsl-slightly-red {
    141   var h/ecx: int <- copy 0
    142   var s/edx: int <- copy 0
    143   var l/ebx: int <- copy 0
    144   h, s, l <- hsl 0xff, 0xfe, 0xfe
    145   check-ints-equal h, 0, "F - test-hsl-slightly-red/hue"
    146   check-ints-equal s, 0xff, "F - test-hsl-slightly-red/saturation"
    147   check-ints-equal l, 0xfe, "F - test-hsl-slightly-red/luminance"  # TODO: should round up
    148 }
    149
    150 fn test-hsl-extremely-red {
    151   var h/ecx: int <- copy 0
    152   var s/edx: int <- copy 0
    153   var l/ebx: int <- copy 0
    154   h, s, l <- hsl 0xff, 0, 0
    155   check-ints-equal h, 0, "F - test-hsl-extremely-red/hue"
    156   check-ints-equal s, 0xff, "F - test-hsl-extremely-red/saturation"
    157   check-ints-equal l, 0x7f, "F - test-hsl-extremely-red/luminance"  # TODO: should round up
    158 }
    159
    160 # green hues: 0x55-0xaa
    161 fn test-hsl-slightly-green {
    162   var h/ecx: int <- copy 0
    163   var s/edx: int <- copy 0
    164   var l/ebx: int <- copy 0
    165   h, s, l <- hsl 0xfe, 0xff, 0xfe
    166   check-ints-equal h, 0x55, "F - test-hsl-slightly-green/hue"
    167   check-ints-equal s, 0xff, "F - test-hsl-slightly-green/saturation"
    168   check-ints-equal l, 0xfe, "F - test-hsl-slightly-green/luminance"  # TODO: should round up
    169 }
    170
    171 fn test-hsl-extremely-green {
    172   var h/ecx: int <- copy 0
    173   var s/edx: int <- copy 0
    174   var l/ebx: int <- copy 0
    175   h, s, l <- hsl 0, 0xff, 0
    176   check-ints-equal h, 0x55, "F - test-hsl-extremely-green/hue"
    177   check-ints-equal s, 0xff, "F - test-hsl-extremely-green/saturation"
    178   check-ints-equal l, 0x7f, "F - test-hsl-extremely-green/luminance"  # TODO: should round up
    179 }
    180
    181 # blue hues: 0xab-0xff
    182 fn test-hsl-slightly-blue {
    183   var h/ecx: int <- copy 0
    184   var s/edx: int <- copy 0
    185   var l/ebx: int <- copy 0
    186   h, s, l <- hsl 0xfe, 0xfe, 0xff
    187   check-ints-equal h, 0xab, "F - test-hsl-slightly-blue/hue"
    188   check-ints-equal s, 0xff, "F - test-hsl-slightly-blue/saturation"
    189   check-ints-equal l, 0xfe, "F - test-hsl-slightly-blue/luminance"  # TODO: should round up
    190 }
    191
    192 fn test-hsl-extremely-blue {
    193   var h/ecx: int <- copy 0
    194   var s/edx: int <- copy 0
    195   var l/ebx: int <- copy 0
    196   h, s, l <- hsl 0, 0, 0xff
    197   check-ints-equal h, 0xab, "F - test-hsl-extremely-blue/hue"
    198   check-ints-equal s, 0xff, "F - test-hsl-extremely-blue/saturation"
    199   check-ints-equal l, 0x7f, "F - test-hsl-extremely-blue/luminance"  # TODO: should round up
    200 }
    201
    202 # cyan: 0x7f
    203
    204 fn test-hsl-cyan {
    205   var h/ecx: int <- copy 0
    206   var s/edx: int <- copy 0
    207   var l/ebx: int <- copy 0
    208   h, s, l <- hsl 0, 0xff, 0xff
    209   check-ints-equal h, 0x80, "F - test-hsl-cyan/hue"
    210   check-ints-equal s, 0xff, "F - test-hsl-cyan/saturation"
    211   check-ints-equal l, 0x7f, "F - test-hsl-cyan/luminance"  # TODO: should round up
    212 }
    213
    214 ###
    215
    216 fn maximum a: int, b: int -> _/eax: int {
    217   var a2/eax: int <- copy a
    218   compare a2, b
    219   {
    220     break-if-<
    221     return a
    222   }
    223   return b
    224 }
    225
    226 fn minimum a: int, b: int -> _/eax: int {
    227   var a2/eax: int <- copy a
    228   compare a2, b
    229   {
    230     break-if->
    231     return a
    232   }
    233   return b
    234 }