5 #include "s2tc_compressor.h"
6 #include "s2tc_common.h"
14 inline bool operator<(const color_t &a, const color_t &b)
26 // 16 differences must fit in int
27 // i.e. a difference must be lower than 2^27
29 // shift right, rounded
30 #define SHRR(a,n) (((a) + (1 << ((n)-1))) >> (n))
32 inline int color_dist_avg(const color_t &a, const color_t &b)
34 int dr = a.r - b.r; // multiplier: 31 (-1..1)
35 int dg = a.g - b.g; // multiplier: 63 (-1..1)
36 int db = a.b - b.b; // multiplier: 31 (-1..1)
37 return ((dr*dr) << 2) + dg*dg + ((db*db) << 2);
40 inline int color_dist_yuv(const color_t &a, const color_t &b)
42 int dr = a.r - b.r; // multiplier: 31 (-1..1)
43 int dg = a.g - b.g; // multiplier: 63 (-1..1)
44 int db = a.b - b.b; // multiplier: 31 (-1..1)
45 int y = dr * 30*2 + dg * 59 + db * 11*2; // multiplier: 6259
46 int u = dr * 202 - y; // * 0.5 / (1 - 0.30)
47 int v = db * 202 - y; // * 0.5 / (1 - 0.11)
48 return ((y*y) << 1) + SHRR(u*u, 3) + SHRR(v*v, 4);
49 // weight for u: sqrt(2^-4) / (0.5 / (1 - 0.30)) = 0.350
50 // weight for v: sqrt(2^-5) / (0.5 / (1 - 0.11)) = 0.315
53 inline int color_dist_rgb(const color_t &a, const color_t &b)
55 int dr = a.r - b.r; // multiplier: 31 (-1..1)
56 int dg = a.g - b.g; // multiplier: 63 (-1..1)
57 int db = a.b - b.b; // multiplier: 31 (-1..1)
58 int y = dr * 21*2 + dg * 72 + db * 7*2; // multiplier: 6272
59 int u = dr * 202 - y; // * 0.5 / (1 - 0.21)
60 int v = db * 202 - y; // * 0.5 / (1 - 0.07)
61 return ((y*y) << 1) + SHRR(u*u, 3) + SHRR(v*v, 4);
62 // weight for u: sqrt(2^-4) / (0.5 / (1 - 0.21)) = 0.395
63 // weight for v: sqrt(2^-5) / (0.5 / (1 - 0.07)) = 0.328
66 inline int color_dist_srgb(const color_t &a, const color_t &b)
68 int dr = a.r * (int) a.r - b.r * (int) b.r; // multiplier: 31*31
69 int dg = a.g * (int) a.g - b.g * (int) b.g; // multiplier: 63*63
70 int db = a.b * (int) a.b - b.b * (int) b.b; // multiplier: 31*31
71 int y = dr * 21*2*2 + dg * 72 + db * 7*2*2; // multiplier: 393400
72 int u = dr * 409 - y; // * 0.5 / (1 - 0.30)
73 int v = db * 409 - y; // * 0.5 / (1 - 0.11)
74 int sy = SHRR(y, 3) * SHRR(y, 4);
75 int su = SHRR(u, 3) * SHRR(u, 4);
76 int sv = SHRR(v, 3) * SHRR(v, 4);
77 return SHRR(sy, 4) + SHRR(su, 8) + SHRR(sv, 9);
78 // weight for u: sqrt(2^-4) / (0.5 / (1 - 0.30)) = 0.350
79 // weight for v: sqrt(2^-5) / (0.5 / (1 - 0.11)) = 0.315
82 inline int srgb_get_y(const color_t &a)
85 int r = a.r * (int) a.r;
86 int g = a.g * (int) a.g;
87 int b = a.b * (int) a.b;
89 int y = 37 * (r * 21*2*2 + g * 72 + b * 7*2*2); // multiplier: 14555800
91 y = sqrt(y); // now in range 0 to 3815
95 inline int color_dist_srgb_mixed(const color_t &a, const color_t &b)
98 int ay = srgb_get_y(a);
99 int by = srgb_get_y(b);
101 int au = a.r * 191 - ay;
102 int av = a.b * 191 - ay;
103 int bu = b.r * 191 - by;
104 int bv = b.b * 191 - by;
109 return ((y*y) << 3) + SHRR(u*u, 1) + SHRR(v*v, 2);
114 // FIXME this is likely broken
115 inline int color_dist_lab_srgb(const color_t &a, const color_t &b)
118 float ar = powf(a.r / 31.0f, 2.4f);
119 float ag = powf(a.g / 63.0f, 2.4f);
120 float ab = powf(a.b / 31.0f, 2.4f);
121 float br = powf(b.r / 31.0f, 2.4f);
122 float bg = powf(b.g / 63.0f, 2.4f);
123 float bb = powf(b.b / 31.0f, 2.4f);
124 // convert to CIE XYZ
125 float aX = 0.4124f * ar + 0.3576f * ag + 0.1805f * ab;
126 float aY = 0.2126f * ar + 0.7152f * ag + 0.0722f * ab;
127 float aZ = 0.0193f * ar + 0.1192f * ag + 0.9505f * ab;
128 float bX = 0.4124f * br + 0.3576f * bg + 0.1805f * bb;
129 float bY = 0.2126f * br + 0.7152f * bg + 0.0722f * bb;
130 float bZ = 0.0193f * br + 0.1192f * bg + 0.9505f * bb;
131 // convert to CIE Lab
135 float aL = 116 * cbrtf(aY / Yn) - 16;
136 float aA = 500 * (cbrtf(aX / Xn) - cbrtf(aY / Yn));
137 float aB = 200 * (cbrtf(aY / Yn) - cbrtf(aZ / Zn));
138 float bL = 116 * cbrtf(bY / Yn) - 16;
139 float bA = 500 * (cbrtf(bX / Xn) - cbrtf(bY / Yn));
140 float bB = 200 * (cbrtf(bY / Yn) - cbrtf(bZ / Zn));
141 // euclidean distance, but moving weight away from A and B
142 return 1000 * ((aL - bL) * (aL - bL) + (aA - bA) * (aA - bA) + (aB - bB) * (aB - bB));
145 inline int color_dist_normalmap(const color_t &a, const color_t &b)
148 ca[0] = a.r / 31.0 * 2 - 1;
149 ca[1] = a.g / 63.0 * 2 - 1;
150 ca[2] = a.b / 31.0 * 2 - 1;
151 cb[0] = b.r / 31.0 * 2 - 1;
152 cb[1] = b.g / 63.0 * 2 - 1;
153 cb[2] = b.b / 31.0 * 2 - 1;
158 (cb[0] - ca[0]) * (cb[0] - ca[0])
160 (cb[1] - ca[1]) * (cb[1] - ca[1])
162 (cb[2] - ca[2]) * (cb[2] - ca[2])
165 // max value: 500 * (4 + 4 + 4) = 6000
168 typedef int ColorDistFunc(const color_t &a, const color_t &b);
170 inline int alpha_dist(unsigned char a, unsigned char b)
172 return (a - (int) b) * (a - (int) b);
175 template <class T, class F>
177 // m: total color count (including non-counted inputs)
179 void reduce_colors_inplace(T *c, int n, int m, F dist)
187 for(i = 0; i < n; ++i)
190 for(j = i+1; j < n; ++j)
192 int d = dist(c[i], c[j]);
193 dists[i][j] = dists[j][i] = d;
199 for(j = 0; j < n; ++j)
201 int d = dist(c[i], c[j]);
205 for(i = 0; i < m; ++i)
206 for(j = i+1; j < m; ++j)
209 for(k = 0; k < n; ++k)
211 int di = dists[i][k];
212 int dj = dists[j][k];
216 if(bestsum < 0 || sum < bestsum)
228 template <class T, class F>
229 void reduce_colors_inplace_2fixpoints(T *c, int n, int m, F dist, const T &fix0, const T &fix1)
237 for(i = 0; i < n; ++i)
240 for(j = i+1; j < n; ++j)
242 int d = dist(c[i], c[j]);
243 dists[i][j] = dists[j][i] = d;
249 for(j = 0; j < n; ++j)
251 int d = dist(c[i], c[j]);
255 // then the two extra rows
256 for(j = 0; j < n; ++j)
258 int d = dist(fix0, c[j]);
261 for(j = 0; j < n; ++j)
263 int d = dist(fix1, c[j]);
266 for(i = 0; i < m; ++i)
267 for(j = i+1; j < m; ++j)
270 for(k = 0; k < n; ++k)
272 int di = dists[i][k];
273 int dj = dists[j][k];
274 int d0 = dists[m][k];
275 int d1 = dists[m+1][k];
276 int m = min(min(di, dj), min(d0, d1));
279 if(bestsum < 0 || sum < bestsum)
292 inline int diffuse(float *diff, float src)
301 void rgb565_image(unsigned char *out, const unsigned char *rgba, int w, int h, int alpharange)
308 for(y = 0; y < h; ++y)
309 for(x = 0; x < w; ++x)
311 out[(x + y * w) * 4 + 2] = diffuse(&diffuse_r, rgba[(x + y * w) * 4 + 2] * 31.0 / 255.0);
312 out[(x + y * w) * 4 + 1] = diffuse(&diffuse_g, rgba[(x + y * w) * 4 + 1] * 63.0 / 255.0);
313 out[(x + y * w) * 4 + 0] = diffuse(&diffuse_b, rgba[(x + y * w) * 4 + 0] * 31.0 / 255.0);
314 out[(x + y * w) * 4 + 3] = diffuse(&diffuse_a, rgba[(x + y * w) * 4 + 3] * (alpharange / 255.0));
318 template<DxtMode dxt, ColorDistFunc ColorDist, bool userandom>
319 void s2tc_encode_block(unsigned char *out, const unsigned char *rgba, int iw, int w, int h, int nrandom)
321 color_t c[16 + (userandom ? nrandom : 0)];
323 unsigned char ca[16];
327 for(x = 0; x < w; ++x)
328 for(y = 0; y < h; ++y)
330 c[n].r = rgba[(x + y * iw) * 4 + 2];
331 c[n].g = rgba[(x + y * iw) * 4 + 1];
332 c[n].b = rgba[(x + y * iw) * 4 + 0];
334 ca[n] = rgba[(x + y * iw) * 4 + 3];
344 for(x = 1; x < n; ++x)
346 mins.r = min(mins.r, c[x].r);
347 mins.g = min(mins.g, c[x].g);
348 mins.b = min(mins.b, c[x].b);
349 maxs.r = max(maxs.r, c[x].r);
350 maxs.g = max(maxs.g, c[x].g);
351 maxs.b = max(maxs.b, c[x].b);
353 color_t len = { maxs.r - mins.r + 1, maxs.g - mins.g + 1, maxs.b - mins.b + 1 };
354 for(x = 0; x < nrandom; ++x)
356 c[m].r = mins.r + rand() % len.r;
357 c[m].g = mins.g + rand() % len.g;
358 c[m].b = mins.b + rand() % len.b;
363 reduce_colors_inplace(c, n, m, ColorDist);
366 reduce_colors_inplace_2fixpoints(ca, n, n, alpha_dist, (unsigned char) 0, (unsigned char) 255);
388 out[8] = ((c[0].g & 0x07) << 5) | c[0].b;
389 out[9] = (c[0].r << 3) | (c[0].g >> 3);
390 out[10] = ((c[1].g & 0x07) << 5) | c[1].b;
391 out[11] = (c[1].r << 3) | (c[1].g >> 3);
394 out[0] = ((c[0].g & 0x07) << 5) | c[0].b;
395 out[1] = (c[0].r << 3) | (c[0].g >> 3);
396 out[2] = ((c[1].g & 0x07) << 5) | c[1].b;
397 out[3] = (c[1].r << 3) | (c[1].g >> 3);
400 for(x = 0; x < w; ++x)
401 for(y = 0; y < h; ++y)
403 int pindex = (x+y*4);
404 c[2].r = rgba[(x + y * iw) * 4 + 2];
405 c[2].g = rgba[(x + y * iw) * 4 + 1];
406 c[2].b = rgba[(x + y * iw) * 4 + 0];
407 ca[2] = rgba[(x + y * iw) * 4 + 3];
413 int bitindex = pindex * 3;
414 da[0] = alpha_dist(ca[0], ca[2]);
415 da[1] = alpha_dist(ca[1], ca[2]);
416 da[2] = alpha_dist(0, ca[2]);
417 da[3] = alpha_dist(255, ca[2]);
418 if(da[2] <= da[0] && da[2] <= da[1] && da[2] <= da[3])
422 out[bitindex / 8 + 2] |= (1 << (bitindex % 8));
424 out[bitindex / 8 + 2] |= (1 << (bitindex % 8));
426 else if(da[3] <= da[0] && da[3] <= da[1])
429 out[bitindex / 8 + 2] |= (1 << (bitindex % 8));
431 out[bitindex / 8 + 2] |= (1 << (bitindex % 8));
433 out[bitindex / 8 + 2] |= (1 << (bitindex % 8));
435 else if(da[0] <= da[1])
442 out[bitindex / 8 + 2] |= (1 << (bitindex % 8));
445 if(ColorDist(c[0], c[2]) > ColorDist(c[1], c[2]))
447 int bitindex = pindex * 2;
448 out[bitindex / 8 + 12] |= (1 << (bitindex % 8));
453 int bitindex = pindex * 4;
454 out[bitindex / 8 + 0] |= (ca[2] << (bitindex % 8));
456 if(ColorDist(c[0], c[2]) > ColorDist(c[1], c[2]))
458 int bitindex = pindex * 2;
459 out[bitindex / 8 + 12] |= (1 << (bitindex % 8));
464 int bitindex = pindex * 2;
466 out[bitindex / 8 + 4] |= (3 << (bitindex % 8));
467 else if(ColorDist(c[0], c[2]) > ColorDist(c[1], c[2]))
468 out[bitindex / 8 + 4] |= (1 << (bitindex % 8));
475 // compile time dispatch magic
476 template<DxtMode dxt, ColorDistFunc ColorDist>
477 void s2tc_encode_block(unsigned char *out, const unsigned char *rgba, int iw, int w, int h, int nrandom)
480 s2tc_encode_block<dxt, ColorDist, true>(out, rgba, iw, w, h, nrandom);
482 s2tc_encode_block<dxt, ColorDist, false>(out, rgba, iw, w, h, nrandom);
485 template<ColorDistFunc ColorDist>
486 void s2tc_encode_block(unsigned char *out, const unsigned char *rgba, int iw, int w, int h, DxtMode dxt, int nrandom)
491 s2tc_encode_block<DXT1, ColorDist>(out, rgba, iw, w, h, nrandom);
494 s2tc_encode_block<DXT3, ColorDist>(out, rgba, iw, w, h, nrandom);
498 s2tc_encode_block<DXT5, ColorDist>(out, rgba, iw, w, h, nrandom);
503 void s2tc_encode_block(unsigned char *out, const unsigned char *rgba, int iw, int w, int h, DxtMode dxt, ColorDistMode cd, int nrandom)
508 s2tc_encode_block<color_dist_rgb>(out, rgba, iw, w, h, dxt, nrandom);
511 s2tc_encode_block<color_dist_yuv>(out, rgba, iw, w, h, dxt, nrandom);
514 s2tc_encode_block<color_dist_srgb>(out, rgba, iw, w, h, dxt, nrandom);
517 s2tc_encode_block<color_dist_srgb_mixed>(out, rgba, iw, w, h, dxt, nrandom);
520 s2tc_encode_block<color_dist_lab_srgb>(out, rgba, iw, w, h, dxt, nrandom);
523 s2tc_encode_block<color_dist_avg>(out, rgba, iw, w, h, dxt, nrandom);
526 s2tc_encode_block<color_dist_normalmap>(out, rgba, iw, w, h, dxt, nrandom);