28f31fcad8ba93bd2a10ffe52fc40616c63d50ec
[blender-staging.git] / source / blender / imbuf / intern / dds / ColorBlock.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributors: Amorilia (amorilia@users.sourceforge.net)
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/imbuf/intern/dds/ColorBlock.cpp
24  *  \ingroup imbdds
25  */
26
27
28 /*
29  * This file is based on a similar file from the NVIDIA texture tools
30  * (http://nvidia-texture-tools.googlecode.com/)
31  *
32  * Original license from NVIDIA follows.
33  */
34
35 // This code is in the public domain -- castanyo@yahoo.es
36
37 #include <ColorBlock.h>
38 #include <Image.h>
39 #include <Common.h>
40
41         // Get approximate luminance.
42         inline static uint colorLuminance(Color32 c)
43         {
44                 return c.r + c.g + c.b;
45         }
46         
47         // Get the euclidean distance between the given colors.
48         inline static uint colorDistance(Color32 c0, Color32 c1)
49         {
50                 return (c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) + (c0.b - c1.b) * (c0.b - c1.b);
51         }
52         
53
54 /// Default constructor.
55 ColorBlock::ColorBlock()
56 {
57 }
58
59 /// Init the color block from an array of colors.
60 ColorBlock::ColorBlock(const uint *linearImage)
61 {
62         for (uint i = 0; i < 16; i++) {
63                 color(i) = Color32(linearImage[i]);
64         }
65 }
66
67 /// Init the color block with the contents of the given block.
68 ColorBlock::ColorBlock(const ColorBlock & block)
69 {
70         for (uint i = 0; i < 16; i++) {
71                 color(i) = block.color(i);
72         }
73 }
74
75
76 /// Initialize this color block.
77 ColorBlock::ColorBlock(const Image *img, uint x, uint y)
78 {
79         init(img, x, y);
80 }
81
82 void ColorBlock::init(const Image *img, uint x, uint y)
83 {
84         init(img->width(), img->height(), (const uint *)img->pixels(), x, y);
85 }
86
87 void ColorBlock::init(uint w, uint h, const uint *data, uint x, uint y)
88 {
89         const uint bw = min(w - x, 4U);
90         const uint bh = min(h - y, 4U);
91
92         // Blocks that are smaller than 4x4 are handled by repeating the pixels.
93         // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
94         // @@ Ideally we should zero the weights of the pixels out of range.
95
96         for (uint i = 0; i < 4; i++) {
97                 const int by = i % bh;
98
99                 for (uint e = 0; e < 4; e++) {
100                         const int bx = e % bw;
101                         const uint idx = (y + by) * w + x + bx;
102
103                         color(e, i).u = data[idx];
104                 }
105         }
106 }
107
108 void ColorBlock::init(uint w, uint h, const float *data, uint x, uint y)
109 {
110         const uint bw = min(w - x, 4U);
111         const uint bh = min(h - y, 4U);
112
113         // Blocks that are smaller than 4x4 are handled by repeating the pixels.
114         // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
115         // @@ Ideally we should zero the weights of the pixels out of range.
116
117         uint srcPlane = w * h;
118
119         for (uint i = 0; i < 4; i++) {
120                 const uint by = i % bh;
121                 
122                 for (uint e = 0; e < 4; e++) {
123                         const uint bx = e % bw;
124                         const uint idx = ((y + by) * w + x + bx);
125                         
126                         Color32 & c = color(e, i);
127                         c.r = uint8(255 * clamp(data[idx + 0 * srcPlane], 0.0f, 1.0f)); // @@ Is this the right way to quantize floats to bytes?
128                         c.g = uint8(255 * clamp(data[idx + 1 * srcPlane], 0.0f, 1.0f));
129                         c.b = uint8(255 * clamp(data[idx + 2 * srcPlane], 0.0f, 1.0f));
130                         c.a = uint8(255 * clamp(data[idx + 3 * srcPlane], 0.0f, 1.0f));
131                 }
132         }
133 }
134
135 static inline uint8 component(Color32 c, uint i)
136 {
137         if (i == 0) return c.r;
138         if (i == 1) return c.g;
139         if (i == 2) return c.b;
140         if (i == 3) return c.a;
141         if (i == 4) return 0xFF;
142         return 0;
143 }
144
145 void ColorBlock::swizzle(uint x, uint y, uint z, uint w)
146 {
147         for (int i = 0; i < 16; i++) {
148                 Color32 c = m_color[i];
149                 m_color[i].r = component(c, x);
150                 m_color[i].g = component(c, y);
151                 m_color[i].b = component(c, z);
152                 m_color[i].a = component(c, w);
153         }
154 }
155
156
157 /// Returns true if the block has a single color.
158 bool ColorBlock::isSingleColor(Color32 mask/*= Color32(0xFF, 0xFF, 0xFF, 0x00)*/) const
159 {
160         uint u = m_color[0].u & mask.u;
161         
162         for (int i = 1; i < 16; i++) {
163                 if (u != (m_color[i].u & mask.u)) {
164                         return false;
165                 }
166         }
167         
168         return true;
169 }
170
171 /*
172 /// Returns true if the block has a single color, ignoring transparent pixels.
173 bool ColorBlock::isSingleColorNoAlpha() const
174 {
175         Color32 c;
176         int i;
177         for (i = 0; i < 16; i++)
178         {
179                 if (m_color[i].a != 0) c = m_color[i];
180         }
181
182         Color32 mask(0xFF, 0xFF, 0xFF, 0x00);
183         uint u = c.u & mask.u;
184
185         for (; i < 16; i++)
186         {
187                 if (u != (m_color[i].u & mask.u))
188                 {
189                         return false;
190                 }
191         }
192         
193         return true;
194 }
195 */
196
197 /// Count number of unique colors in this color block.
198 /*uint ColorBlock::countUniqueColors() const
199 {
200         uint count = 0;
201
202         // @@ This does not have to be o(n^2)
203         for (int i = 0; i < 16; i++)
204         {
205                 bool unique = true;
206                 for (int j = 0; j < i; j++) {
207                         if ( m_color[i] != m_color[j] ) {
208                                 unique = false;
209                         }
210                 }
211                 
212                 if ( unique ) {
213                         count++;
214                 }
215         }
216         
217         return count;
218 }*/
219
220 /*/// Get average color of the block.
221 Color32 ColorBlock::averageColor() const
222 {
223         uint r, g, b, a;
224         r = g = b = a = 0;
225
226         for (uint i = 0; i < 16; i++) {
227                 r += m_color[i].r;
228                 g += m_color[i].g;
229                 b += m_color[i].b;
230                 a += m_color[i].a;
231         }
232         
233         return Color32(uint8(r / 16), uint8(g / 16), uint8(b / 16), uint8(a / 16));
234 }*/
235
236 /// Return true if the block is not fully opaque.
237 bool ColorBlock::hasAlpha() const
238 {
239         for (uint i = 0; i < 16; i++) {
240                 if (m_color[i].a != 255) return true;
241         }
242         return false;
243 }
244
245 #if 0
246
247 /// Get diameter color range.
248 void ColorBlock::diameterRange(Color32 *start, Color32 *end) const
249 {
250         Color32 c0, c1;
251         uint best_dist = 0;
252         
253         for (int i = 0; i < 16; i++) {
254                 for (int j = i+1; j < 16; j++) {
255                         uint dist = colorDistance(m_color[i], m_color[j]);
256                         if ( dist > best_dist ) {
257                                 best_dist = dist;
258                                 c0 = m_color[i];
259                                 c1 = m_color[j];
260                         }
261                 }
262         }
263         
264         *start = c0;
265         *end = c1;
266 }
267
268 /// Get luminance color range.
269 void ColorBlock::luminanceRange(Color32 *start, Color32 *end) const
270 {
271         Color32 minColor, maxColor;
272         uint minLuminance, maxLuminance;
273         
274         maxLuminance = minLuminance = colorLuminance(m_color[0]);
275         
276         for (uint i = 1; i < 16; i++)
277         {
278                 uint luminance = colorLuminance(m_color[i]);
279                 
280                 if (luminance > maxLuminance) {
281                         maxLuminance = luminance;
282                         maxColor = m_color[i];
283                 }
284                 else if (luminance < minLuminance) {
285                         minLuminance = luminance;
286                         minColor = m_color[i];
287                 }
288         }
289
290         *start = minColor;
291         *end = maxColor;
292 }
293
294 /// Get color range based on the bounding box. 
295 void ColorBlock::boundsRange(Color32 *start, Color32 *end) const
296 {
297         Color32 minColor(255, 255, 255);
298         Color32 maxColor(0, 0, 0);
299
300         for (uint i = 0; i < 16; i++)
301         {
302                 if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; }
303                 if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; }
304                 if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; }
305                 if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; }
306                 if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; }
307                 if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; }
308         }
309
310         // Offset range by 1/16 of the extents
311         Color32 inset;
312         inset.r = (maxColor.r - minColor.r) >> 4;
313         inset.g = (maxColor.g - minColor.g) >> 4;
314         inset.b = (maxColor.b - minColor.b) >> 4;
315
316         minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
317         minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
318         minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
319
320         maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
321         maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
322         maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
323
324         *start = minColor;
325         *end = maxColor;
326 }
327
328 /// Get color range based on the bounding box. 
329 void ColorBlock::boundsRangeAlpha(Color32 *start, Color32 *end) const
330 {
331         Color32 minColor(255, 255, 255, 255);
332         Color32 maxColor(0, 0, 0, 0);
333
334         for (uint i = 0; i < 16; i++)
335         {
336                 if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; }
337                 if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; }
338                 if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; }
339                 if (m_color[i].a < minColor.a) { minColor.a = m_color[i].a; }
340                 if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; }
341                 if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; }
342                 if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; }
343                 if (m_color[i].a > maxColor.a) { maxColor.a = m_color[i].a; }
344         }
345
346         // Offset range by 1/16 of the extents
347         Color32 inset;
348         inset.r = (maxColor.r - minColor.r) >> 4;
349         inset.g = (maxColor.g - minColor.g) >> 4;
350         inset.b = (maxColor.b - minColor.b) >> 4;
351         inset.a = (maxColor.a - minColor.a) >> 4;
352
353         minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
354         minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
355         minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
356         minColor.a = (minColor.a + inset.a <= 255) ? minColor.a + inset.a : 255;
357
358         maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
359         maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
360         maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
361         maxColor.a = (maxColor.a >= inset.a) ? maxColor.a - inset.a : 0;
362         
363         *start = minColor;
364         *end = maxColor;
365 }
366 #endif
367
368 /*/// Sort colors by abosolute value in their 16 bit representation.
369 void ColorBlock::sortColorsByAbsoluteValue()
370 {
371         // Dummy selection sort.
372         for ( uint a = 0; a < 16; a++ ) {
373                 uint max = a;
374                 Color16 cmax(m_color[a]);
375                 
376                 for ( uint b = a+1; b < 16; b++ ) {
377                         Color16 cb(m_color[b]);
378                         
379                         if ( cb.u > cmax.u ) {
380                                 max = b;
381                                 cmax = cb;
382                         }
383                 }
384                 swap( m_color[a], m_color[max] );
385         }
386 }*/
387
388
389 /*/// Find extreme colors in the given axis.
390 void ColorBlock::computeRange(Vector3::Arg axis, Color32 *start, Color32 *end) const
391 {
392         
393         int mini, maxi;
394         mini = maxi = 0;
395         
396         float min, max;
397         min = max = dot(Vector3(m_color[0].r, m_color[0].g, m_color[0].b), axis);
398
399         for (uint i = 1; i < 16; i++)
400         {
401                 const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
402                 
403                 float val = dot(vec, axis);
404                 if ( val < min ) {
405                         mini = i;
406                         min = val;
407                 }
408                 else if ( val > max ) {
409                         maxi = i;
410                         max = val;
411                 }
412         }
413         
414         *start = m_color[mini];
415         *end = m_color[maxi];
416 }*/
417
418
419 /*/// Sort colors in the given axis.
420 void ColorBlock::sortColors(const Vector3 & axis)
421 {
422         float luma_array[16];
423         
424         for (uint i = 0; i < 16; i++) {
425                 const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
426                 luma_array[i] = dot(vec, axis);
427         }
428         
429         // Dummy selection sort.
430         for ( uint a = 0; a < 16; a++ ) {
431                 uint min = a;
432                 for ( uint b = a+1; b < 16; b++ ) {
433                         if ( luma_array[b] < luma_array[min] ) {
434                                 min = b;
435                         }
436                 }
437                 swap( luma_array[a], luma_array[min] );
438                 swap( m_color[a], m_color[min] );
439         }
440 }*/
441
442
443 /*/// Get the volume of the color block.
444 float ColorBlock::volume() const
445 {
446         Box bounds;
447         bounds.clearBounds();
448         
449         for (int i = 0; i < 16; i++) {
450                 const Vector3 point(m_color[i].r, m_color[i].g, m_color[i].b);
451                 bounds.addPointToBounds(point);
452         }
453         
454         return bounds.volume();
455 }
456 */
457