https://github.com/akkartik/mu/blob/main/505colors.mu
1 fn nearest-color-euclidean r: int, g: int, b: int -> _/eax: int {
2 var result/edi: int <- copy 0x100/invalid
3 var max-distance/esi: int <- copy 0x30000/max
4 var r2/ecx: int <- copy 0
5 var g2/edx: int <- copy 0
6 var b2/ebx: int <- copy 0
7 var color/eax: int <- copy 0
8 {
9 compare color, 0x100
10 break-if->=
11 $nearest-color-euclidean:body: {
12 r2, g2, b2 <- color-rgb color
13 {
14 var curr-distance/eax: int <- euclidean-distance-squared r, g, b, r2, g2, b2
15 compare curr-distance, max-distance
16 break-if->= $nearest-color-euclidean:body
17 max-distance <- copy curr-distance
18 }
19 result <- copy color
20 }
21 color <- increment
22 loop
23 }
24 return result
25 }
26
27 fn euclidean-distance-squared r1: int, g1: int, b1: int, r2: int, g2: int, b2: int -> _/eax: int {
28 var result/edi: int <- copy 0
29
30 var tmp/eax: int <- copy r1
31 tmp <- subtract r2
32 tmp <- multiply tmp
33 result <- add tmp
34
35 tmp <- copy g1
36 tmp <- subtract g2
37 tmp <- multiply tmp
38 result <- add tmp
39
40 tmp <- copy b1
41 tmp <- subtract b2
42 tmp <- multiply tmp
43 result <- add tmp
44 return result
45 }
46
47
48
49
50
51 fn hsl r: int, g: int, b: int -> _/ecx: int, _/edx: int, _/ebx: int {
52 var _max/eax: int <- maximum r, g
53 _max <- maximum _max, b
54 var max/ecx: int <- copy _max
55 var _min/eax: int <- minimum r, g
56 _min <- minimum _min, b
57 var min/edx: int <- copy _min
58 var luminance/ebx: int <- copy min
59 luminance <- add max
60 luminance <- shift-right 1
61
62 compare min, max
63 {
64 break-if-!=
65 return 0, 0, luminance
66 }
67
68
69
70 var nr/esi: int <- copy max
71 nr <- subtract min
72 var dr/eax: int <- copy 0
73 compare luminance, 0x80
74 {
75 break-if->=
76 dr <- copy max
77 dr <- add min
78 }
79 {
80 break-if-<
81 dr <- copy 0xff
82 dr <- shift-left 1
83 dr <- subtract max
84 dr <- subtract min
85 }
86 var q/xmm0: float <- convert nr
87 var tmp/xmm1: float <- convert dr
88 q <- divide tmp
89 var int-255/eax: int <- copy 0xff
90 tmp <- convert int-255
91 q <- multiply tmp
92 var saturation/esi: int <- convert q
93
94
95
96
97 var zero/eax: int <- copy 0
98 var hue-f/xmm0: float <- convert zero
99 var dr/eax: int <- copy max
100 dr <- subtract min
101 var dr-f/xmm1: float <- convert dr
102 $hsl:compute-hue-normalized: {
103 compare r, max
104 {
105 break-if-!=
106 var nr/eax: int <- copy g
107 nr <- subtract b
108 hue-f <- convert nr
109 hue-f <- divide dr-f
110 break $hsl:compute-hue-normalized
111 }
112 compare g, max
113 {
114 break-if-!=
115 var nr/eax: int <- copy b
116 nr <- subtract r
117 var f/xmm2: float <- convert nr
118 f <- divide dr-f
119 var two/ecx: int <- copy 2
120 hue-f <- convert two
121 hue-f <- add f
122 break $hsl:compute-hue-normalized
123 }
124 compare b, max
125 {
126 break-if-!=
127 var nr/eax: int <- copy r
128 nr <- subtract g
129 var f/xmm2: float <- convert nr
130 f <- divide dr-f
131 var two/ecx: int <- copy 4
132 hue-f <- convert two
133 hue-f <- add f
134 break $hsl:compute-hue-normalized
135 }
136 }
137 var int-256/eax: int <- copy 0x100
138 var scaling-factor/xmm1: float <- convert int-256
139 var int-6/eax: int <- copy 6
140 var six-f/xmm2: float <- convert int-6
141 scaling-factor <- divide six-f
142 hue-f <- multiply scaling-factor
143 var hue/eax: int <- convert hue-f
144
145 compare hue, 0
146 {
147 break-if->=
148 var tmp/ecx: int <- copy 0x100
149 tmp <- subtract hue
150 hue <- copy tmp
151 }
152 return hue, saturation, luminance
153 }
154
155 fn test-hsl-black {
156 var h/ecx: int <- copy 0
157 var s/edx: int <- copy 0
158 var l/ebx: int <- copy 0
159 h, s, l <- hsl 0, 0, 0
160 check-ints-equal h, 0, "F - test-hsl-black/hue"
161 check-ints-equal s, 0, "F - test-hsl-black/saturation"
162 check-ints-equal l, 0, "F - test-hsl-black/luminance"
163 }
164
165 fn test-hsl-white {
166 var h/ecx: int <- copy 0
167 var s/edx: int <- copy 0
168 var l/ebx: int <- copy 0
169 h, s, l <- hsl 0xff, 0xff, 0xff
170 check-ints-equal h, 0, "F - test-hsl-white/hue"
171 check-ints-equal s, 0, "F - test-hsl-white/saturation"
172 check-ints-equal l, 0xff, "F - test-hsl-white/luminance"
173 }
174
175 fn test-hsl-grey {
176 var h/ecx: int <- copy 0
177 var s/edx: int <- copy 0
178 var l/ebx: int <- copy 0
179 h, s, l <- hsl 0x30, 0x30, 0x30
180 check-ints-equal h, 0, "F - test-hsl-grey/hue"
181 check-ints-equal s, 0, "F - test-hsl-grey/saturation"
182 check-ints-equal l, 0x30, "F - test-hsl-grey/luminance"
183 }
184
185
186 fn test-hsl-slightly-red {
187 var h/ecx: int <- copy 0
188 var s/edx: int <- copy 0
189 var l/ebx: int <- copy 0
190 h, s, l <- hsl 0xff, 0xfe, 0xfe
191 check-ints-equal h, 0, "F - test-hsl-slightly-red/hue"
192 check-ints-equal s, 0xff, "F - test-hsl-slightly-red/saturation"
193 check-ints-equal l, 0xfe, "F - test-hsl-slightly-red/luminance"
194 }
195
196 fn test-hsl-extremely-red {
197 var h/ecx: int <- copy 0
198 var s/edx: int <- copy 0
199 var l/ebx: int <- copy 0
200 h, s, l <- hsl 0xff, 0, 0
201 check-ints-equal h, 0, "F - test-hsl-extremely-red/hue"
202 check-ints-equal s, 0xff, "F - test-hsl-extremely-red/saturation"
203 check-ints-equal l, 0x7f, "F - test-hsl-extremely-red/luminance"
204 }
205
206
207 fn test-hsl-slightly-green {
208 var h/ecx: int <- copy 0
209 var s/edx: int <- copy 0
210 var l/ebx: int <- copy 0
211 h, s, l <- hsl 0xfe, 0xff, 0xfe
212 check-ints-equal h, 0x55, "F - test-hsl-slightly-green/hue"
213 check-ints-equal s, 0xff, "F - test-hsl-slightly-green/saturation"
214 check-ints-equal l, 0xfe, "F - test-hsl-slightly-green/luminance"
215 }
216
217 fn test-hsl-extremely-green {
218 var h/ecx: int <- copy 0
219 var s/edx: int <- copy 0
220 var l/ebx: int <- copy 0
221 h, s, l <- hsl 0, 0xff, 0
222 check-ints-equal h, 0x55, "F - test-hsl-extremely-green/hue"
223 check-ints-equal s, 0xff, "F - test-hsl-extremely-green/saturation"
224 check-ints-equal l, 0x7f, "F - test-hsl-extremely-green/luminance"
225 }
226
227
228 fn test-hsl-slightly-blue {
229 var h/ecx: int <- copy 0
230 var s/edx: int <- copy 0
231 var l/ebx: int <- copy 0
232 h, s, l <- hsl 0xfe, 0xfe, 0xff
233 check-ints-equal h, 0xab, "F - test-hsl-slightly-blue/hue"
234 check-ints-equal s, 0xff, "F - test-hsl-slightly-blue/saturation"
235 check-ints-equal l, 0xfe, "F - test-hsl-slightly-blue/luminance"
236 }
237
238 fn test-hsl-extremely-blue {
239 var h/ecx: int <- copy 0
240 var s/edx: int <- copy 0
241 var l/ebx: int <- copy 0
242 h, s, l <- hsl 0, 0, 0xff
243 check-ints-equal h, 0xab, "F - test-hsl-extremely-blue/hue"
244 check-ints-equal s, 0xff, "F - test-hsl-extremely-blue/saturation"
245 check-ints-equal l, 0x7f, "F - test-hsl-extremely-blue/luminance"
246 }
247
248
249
250 fn test-hsl-cyan {
251 var h/ecx: int <- copy 0
252 var s/edx: int <- copy 0
253 var l/ebx: int <- copy 0
254 h, s, l <- hsl 0, 0xff, 0xff
255 check-ints-equal h, 0x80, "F - test-hsl-cyan/hue"
256 check-ints-equal s, 0xff, "F - test-hsl-cyan/saturation"
257 check-ints-equal l, 0x7f, "F - test-hsl-cyan/luminance"
258 }
259
260 fn nearest-color-euclidean-hsl h: int, s: int, l: int -> _/eax: int {
261 var result/edi: int <- copy 0x100/invalid
262 var max-distance/esi: int <- copy 0x30000/max
263 var a/ecx: int <- copy 0
264 var b/edx: int <- copy 0
265 var c/ebx: int <- copy 0
266 var color/eax: int <- copy 0
267 {
268 compare color, 0x100
269 break-if->=
270 $nearest-color-euclidean-hsl:body: {
271 a, b, c <- color-rgb color
272 a, b, c <- hsl a, b, c
273 {
274 var curr-distance/eax: int <- euclidean-hsl-squared a, b, c, h, s, l
275 compare curr-distance, max-distance
276 break-if->= $nearest-color-euclidean-hsl:body
277 max-distance <- copy curr-distance
278 }
279 result <- copy color
280 }
281 color <- increment
282 loop
283 }
284 return result
285 }
286
287 fn test-nearest-color-euclidean-hsl {
288
289 var red/eax: int <- nearest-color-euclidean-hsl 0, 0xff, 0xff
290 check-ints-equal red, 0x58/88, "F - test-nearest-color-euclidean-hsl/full-red1"
291 red <- nearest-color-euclidean-hsl 0, 0xff, 0xc0
292 check-ints-equal red, 0x40/64, "F - test-nearest-color-euclidean-hsl/full-red2"
293 red <- nearest-color-euclidean-hsl 0, 0xff, 0x80
294 check-ints-equal red, 0x28/40, "F - test-nearest-color-euclidean-hsl/full-red3"
295 red <- nearest-color-euclidean-hsl 0, 0xff, 0x40
296 check-ints-equal red, 0x28/40, "F - test-nearest-color-euclidean-hsl/full-red4"
297 red <- nearest-color-euclidean-hsl 0, 0xff, 0
298 check-ints-equal red, 0x28/40, "F - test-nearest-color-euclidean-hsl/full-red5"
299
300 red <- nearest-color-euclidean-hsl 0xff, 0xff, 0xff
301
302 check-ints-equal red, 0x57/87, "F - test-nearest-color-euclidean-hsl/other-end-of-red"
303
304 red <- nearest-color-euclidean-hsl 0, 0x80, 0xff
305 check-ints-equal red, 0xf/15, "F - test-nearest-color-euclidean-hsl/half-red1"
306 red <- nearest-color-euclidean-hsl 0, 0x80, 0xc0
307 check-ints-equal red, 4, "F - test-nearest-color-euclidean-hsl/half-red2"
308 red <- nearest-color-euclidean-hsl 0, 0x80, 0x80
309 check-ints-equal red, 4, "F - test-nearest-color-euclidean-hsl/half-red3"
310 red <- nearest-color-euclidean-hsl 0, 0x80, 0x40
311 check-ints-equal red, 4, "F - test-nearest-color-euclidean-hsl/half-red4"
312 red <- nearest-color-euclidean-hsl 0, 0x80, 0
313 check-ints-equal red, 0x70/112, "F - test-nearest-color-euclidean-hsl/half-red5"
314 }
315
316 fn euclidean-hsl-squared h1: int, s1: int, l1: int, h2: int, s2: int, l2: int -> _/eax: int {
317 var result/edi: int <- copy 0
318
319 var tmp/eax: int <- copy h1
320 tmp <- subtract h2
321 tmp <- multiply tmp
322
323
324 result <- add tmp
325
326 tmp <- copy s1
327 tmp <- subtract s2
328 tmp <- multiply tmp
329 result <- add tmp
330
331 tmp <- copy l1
332 tmp <- subtract l2
333 tmp <- multiply tmp
334 result <- add tmp
335 return result
336 }
337
338
339
340 fn maximum a: int, b: int -> _/eax: int {
341 var a2/eax: int <- copy a
342 compare a2, b
343 {
344 break-if-<
345 return a
346 }
347 return b
348 }
349
350 fn minimum a: int, b: int -> _/eax: int {
351 var a2/eax: int <- copy a
352 compare a2, b
353 {
354 break-if->
355 return a
356 }
357 return b
358 }