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 }