|
Blender
V2.59
|
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