Blender V2.61 - r43446

ColorBlock.cpp

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