Blender V2.61 - r43446
|
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