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