Blender  V2.59
ColorBlock.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: ColorBlock.cpp 36546 2011-05-08 09:05:52Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * Contributors: Amorilia (amorilia@users.sourceforge.net)
00021  *
00022  * ***** END GPL LICENSE BLOCK *****
00023  */
00024 
00030 /*
00031  * This file is based on a similar file from the NVIDIA texture tools
00032  * (http://nvidia-texture-tools.googlecode.com/)
00033  *
00034  * Original license from NVIDIA follows.
00035  */
00036 
00037 // This code is in the public domain -- castanyo@yahoo.es
00038 
00039 #include <ColorBlock.h>
00040 #include <Image.h>
00041 #include <Common.h>
00042 
00043         // Get approximate luminance.
00044         inline static uint colorLuminance(Color32 c)
00045         {
00046                 return c.r + c.g + c.b;
00047         }
00048         
00049         // Get the euclidean distance between the given colors.
00050         inline static uint colorDistance(Color32 c0, Color32 c1)
00051         {
00052                 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);
00053         }
00054         
00055 
00057 ColorBlock::ColorBlock()
00058 {
00059 }
00060 
00062 ColorBlock::ColorBlock(const uint * linearImage)
00063 {
00064         for(uint i = 0; i < 16; i++) {
00065                 color(i) = Color32(linearImage[i]);
00066         }
00067 }
00068 
00070 ColorBlock::ColorBlock(const ColorBlock & block)
00071 {
00072         for(uint i = 0; i < 16; i++) {
00073                 color(i) = block.color(i);
00074         }
00075 }
00076 
00077 
00079 ColorBlock::ColorBlock(const Image * img, uint x, uint y)
00080 {
00081         init(img, x, y);
00082 }
00083 
00084 void ColorBlock::init(const Image * img, uint x, uint y)
00085 {
00086     init(img->width(), img->height(), (const uint *)img->pixels(), x, y);
00087 }
00088 
00089 void ColorBlock::init(uint w, uint h, const uint * data, uint x, uint y)
00090 {
00091         const uint bw = min(w - x, 4U);
00092         const uint bh = min(h - y, 4U);
00093 
00094     // Blocks that are smaller than 4x4 are handled by repeating the pixels.
00095     // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
00096     // @@ Ideally we should zero the weights of the pixels out of range.
00097 
00098     for (uint i = 0; i < 4; i++)
00099     {
00100         const int by = i % bh;
00101 
00102         for (uint e = 0; e < 4; e++)
00103         {
00104             const int bx = e % bw;
00105             const uint idx = (y + by) * w + x + bx;
00106 
00107             color(e, i).u = data[idx];
00108         }
00109     }
00110 }
00111 
00112 void ColorBlock::init(uint w, uint h, const float * data, uint x, uint y)
00113 {
00114     const uint bw = min(w - x, 4U);
00115     const uint bh = min(h - y, 4U);
00116 
00117         // Blocks that are smaller than 4x4 are handled by repeating the pixels.
00118         // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
00119     // @@ Ideally we should zero the weights of the pixels out of range.
00120 
00121     uint srcPlane = w * h;
00122 
00123         for (uint i = 0; i < 4; i++)
00124         {
00125                 const uint by = i % bh;
00126                 
00127                 for (uint e = 0; e < 4; e++)
00128                 {
00129                         const uint bx = e % bw;
00130             const uint idx = ((y + by) * w + x + bx);
00131                         
00132                         Color32 & c = color(e, i);
00133             c.r = uint8(255 * clamp(data[idx + 0 * srcPlane], 0.0f, 1.0f)); // @@ Is this the right way to quantize floats to bytes?
00134             c.g = uint8(255 * clamp(data[idx + 1 * srcPlane], 0.0f, 1.0f));
00135             c.b = uint8(255 * clamp(data[idx + 2 * srcPlane], 0.0f, 1.0f));
00136             c.a = uint8(255 * clamp(data[idx + 3 * srcPlane], 0.0f, 1.0f));
00137                 }
00138         }
00139 }
00140 
00141 static inline uint8 component(Color32 c, uint i)
00142 {
00143         if (i == 0) return c.r;
00144         if (i == 1) return c.g;
00145         if (i == 2) return c.b;
00146         if (i == 3) return c.a;
00147         if (i == 4) return 0xFF;
00148         return 0;
00149 }
00150 
00151 void ColorBlock::swizzle(uint x, uint y, uint z, uint w)
00152 {
00153         for (int i = 0; i < 16; i++)
00154         {
00155                 Color32 c = m_color[i];
00156                 m_color[i].r = component(c, x);
00157                 m_color[i].g = component(c, y);
00158                 m_color[i].b = component(c, z);
00159                 m_color[i].a = component(c, w);
00160         }
00161 }
00162 
00163 
00165 bool ColorBlock::isSingleColor(Color32 mask/*= Color32(0xFF, 0xFF, 0xFF, 0x00)*/) const
00166 {
00167         uint u = m_color[0].u & mask.u;
00168         
00169         for (int i = 1; i < 16; i++)
00170         {
00171                 if (u != (m_color[i].u & mask.u))
00172                 {
00173                         return false;
00174                 }
00175         }
00176         
00177         return true;
00178 }
00179 
00180 /*
00182 bool ColorBlock::isSingleColorNoAlpha() const
00183 {
00184         Color32 c;
00185         int i;
00186         for(i = 0; i < 16; i++)
00187         {
00188         if (m_color[i].a != 0) c = m_color[i];
00189         }
00190 
00191         Color32 mask(0xFF, 0xFF, 0xFF, 0x00);
00192         uint u = c.u & mask.u;
00193 
00194         for(; i < 16; i++)
00195         {
00196                 if (u != (m_color[i].u & mask.u))
00197                 {
00198                         return false;
00199                 }
00200         }
00201         
00202         return true;
00203 }
00204 */
00205 
00207 /*uint ColorBlock::countUniqueColors() const
00208 {
00209         uint count = 0;
00210 
00211         // @@ This does not have to be o(n^2)
00212         for(int i = 0; i < 16; i++)
00213         {
00214                 bool unique = true;
00215                 for(int j = 0; j < i; j++) {
00216                         if( m_color[i] != m_color[j] ) {
00217                                 unique = false;
00218                         }
00219                 }
00220                 
00221                 if( unique ) {
00222                         count++;
00223                 }
00224         }
00225         
00226         return count;
00227 }*/
00228 
00229 /*/// Get average color of the block.
00230 Color32 ColorBlock::averageColor() const
00231 {
00232         uint r, g, b, a;
00233         r = g = b = a = 0;
00234 
00235         for(uint i = 0; i < 16; i++) {
00236                 r += m_color[i].r;
00237                 g += m_color[i].g;
00238                 b += m_color[i].b;
00239                 a += m_color[i].a;
00240         }
00241         
00242         return Color32(uint8(r / 16), uint8(g / 16), uint8(b / 16), uint8(a / 16));
00243 }*/
00244 
00246 bool ColorBlock::hasAlpha() const
00247 {
00248         for (uint i = 0; i < 16; i++)
00249         {
00250                 if (m_color[i].a != 255) return true;
00251         }
00252         return false;
00253 }
00254 
00255 #if 0
00256 
00258 void ColorBlock::diameterRange(Color32 * start, Color32 * end) const
00259 {
00260         Color32 c0, c1;
00261         uint best_dist = 0;
00262         
00263         for(int i = 0; i < 16; i++) {
00264                 for (int j = i+1; j < 16; j++) {
00265                         uint dist = colorDistance(m_color[i], m_color[j]);
00266                         if( dist > best_dist ) {
00267                                 best_dist = dist;
00268                                 c0 = m_color[i];
00269                                 c1 = m_color[j];
00270                         }
00271                 }
00272         }
00273         
00274         *start = c0;
00275         *end = c1;
00276 }
00277 
00279 void ColorBlock::luminanceRange(Color32 * start, Color32 * end) const
00280 {
00281         Color32 minColor, maxColor;
00282         uint minLuminance, maxLuminance;
00283         
00284         maxLuminance = minLuminance = colorLuminance(m_color[0]);
00285         
00286         for(uint i = 1; i < 16; i++)
00287         {
00288                 uint luminance = colorLuminance(m_color[i]);
00289                 
00290                 if (luminance > maxLuminance) {
00291                         maxLuminance = luminance;
00292                         maxColor = m_color[i];
00293                 }
00294                 else if (luminance < minLuminance) {
00295                         minLuminance = luminance;
00296                         minColor = m_color[i];
00297                 }
00298         }
00299 
00300         *start = minColor;
00301         *end = maxColor;
00302 }
00303 
00305 void ColorBlock::boundsRange(Color32 * start, Color32 * end) const
00306 {
00307         Color32 minColor(255, 255, 255);
00308         Color32 maxColor(0, 0, 0);
00309 
00310         for(uint i = 0; i < 16; i++)
00311         {
00312                 if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; }
00313                 if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; }
00314                 if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; }
00315                 if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; }
00316                 if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; }
00317                 if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; }
00318         }
00319 
00320         // Offset range by 1/16 of the extents
00321         Color32 inset;
00322         inset.r = (maxColor.r - minColor.r) >> 4;
00323         inset.g = (maxColor.g - minColor.g) >> 4;
00324         inset.b = (maxColor.b - minColor.b) >> 4;
00325 
00326         minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
00327         minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
00328         minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
00329 
00330         maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
00331         maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
00332         maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
00333 
00334         *start = minColor;
00335         *end = maxColor;
00336 }
00337 
00339 void ColorBlock::boundsRangeAlpha(Color32 * start, Color32 * end) const
00340 {
00341         Color32 minColor(255, 255, 255, 255);
00342         Color32 maxColor(0, 0, 0, 0);
00343 
00344         for(uint i = 0; i < 16; i++)
00345         {
00346                 if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; }
00347                 if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; }
00348                 if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; }
00349                 if (m_color[i].a < minColor.a) { minColor.a = m_color[i].a; }
00350                 if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; }
00351                 if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; }
00352                 if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; }
00353                 if (m_color[i].a > maxColor.a) { maxColor.a = m_color[i].a; }
00354         }
00355 
00356         // Offset range by 1/16 of the extents
00357         Color32 inset;
00358         inset.r = (maxColor.r - minColor.r) >> 4;
00359         inset.g = (maxColor.g - minColor.g) >> 4;
00360         inset.b = (maxColor.b - minColor.b) >> 4;
00361         inset.a = (maxColor.a - minColor.a) >> 4;
00362 
00363         minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
00364         minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
00365         minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
00366         minColor.a = (minColor.a + inset.a <= 255) ? minColor.a + inset.a : 255;
00367 
00368         maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
00369         maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
00370         maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
00371         maxColor.a = (maxColor.a >= inset.a) ? maxColor.a - inset.a : 0;
00372         
00373         *start = minColor;
00374         *end = maxColor;
00375 }
00376 #endif
00377 
00378 /*/// Sort colors by abosolute value in their 16 bit representation.
00379 void ColorBlock::sortColorsByAbsoluteValue()
00380 {
00381         // Dummy selection sort.
00382         for( uint a = 0; a < 16; a++ ) {
00383                 uint max = a;
00384                 Color16 cmax(m_color[a]);
00385                 
00386                 for( uint b = a+1; b < 16; b++ ) {
00387                         Color16 cb(m_color[b]);
00388                         
00389                         if( cb.u > cmax.u ) {
00390                                 max = b;
00391                                 cmax = cb;
00392                         }
00393                 }
00394                 swap( m_color[a], m_color[max] );
00395         }
00396 }*/
00397 
00398 
00399 /*/// Find extreme colors in the given axis.
00400 void ColorBlock::computeRange(Vector3::Arg axis, Color32 * start, Color32 * end) const
00401 {
00402         
00403         int mini, maxi;
00404         mini = maxi = 0;
00405         
00406         float min, max; 
00407         min = max = dot(Vector3(m_color[0].r, m_color[0].g, m_color[0].b), axis);
00408 
00409         for(uint i = 1; i < 16; i++)
00410         {
00411                 const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
00412                 
00413                 float val = dot(vec, axis);
00414                 if( val < min ) {
00415                         mini = i;
00416                         min = val;
00417                 }
00418                 else if( val > max ) {
00419                         maxi = i;
00420                         max = val;
00421                 }
00422         }
00423         
00424         *start = m_color[mini];
00425         *end = m_color[maxi];
00426 }*/
00427 
00428 
00429 /*/// Sort colors in the given axis.
00430 void ColorBlock::sortColors(const Vector3 & axis)
00431 {
00432         float luma_array[16];
00433         
00434         for(uint i = 0; i < 16; i++) {
00435                 const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
00436                 luma_array[i] = dot(vec, axis);
00437         }
00438         
00439         // Dummy selection sort.
00440         for( uint a = 0; a < 16; a++ ) {
00441                 uint min = a;
00442                 for( uint b = a+1; b < 16; b++ ) {
00443                         if( luma_array[b] < luma_array[min] ) {
00444                                 min = b;
00445                         }
00446                 }
00447                 swap( luma_array[a], luma_array[min] );
00448                 swap( m_color[a], m_color[min] );
00449         }
00450 }*/
00451 
00452 
00453 /*/// Get the volume of the color block.
00454 float ColorBlock::volume() const
00455 {
00456         Box bounds;
00457         bounds.clearBounds();
00458         
00459         for(int i = 0; i < 16; i++) {
00460                 const Vector3 point(m_color[i].r, m_color[i].g, m_color[i].b);
00461                 bounds.addPointToBounds(point);
00462         }
00463         
00464         return bounds.volume();
00465 }
00466 */
00467