00001
00032 #include "linden_common.h"
00033
00034 #include "llimage.h"
00035
00036 #include "llmath.h"
00037 #include "v4coloru.h"
00038 #include "llmemtype.h"
00039
00040 #include "llimagebmp.h"
00041 #include "llimagetga.h"
00042 #include "llimagej2c.h"
00043 #if JPEG_SUPPORT
00044 #include "llimagejpeg.h"
00045 #endif
00046 #include "llimagedxt.h"
00047
00048
00049
00050
00051
00052 LLImageBase::LLImageBase()
00053 : mData(NULL),
00054 mDataSize(0),
00055 mWidth(0),
00056 mHeight(0),
00057 mComponents(0),
00058 mMemType(LLMemType::MTYPE_IMAGEBASE)
00059 {
00060 }
00061
00062
00063 LLImageBase::~LLImageBase()
00064 {
00065 deleteData();
00066 }
00067
00068
00069 void LLImageBase::dump()
00070 {
00071 llinfos << "LLImageBase mComponents " << mComponents
00072 << " mData " << mData
00073 << " mDataSize " << mDataSize
00074 << " mWidth " << mWidth
00075 << " mHeight " << mHeight
00076 << llendl;
00077 }
00078
00079
00080 void LLImageBase::sanityCheck()
00081 {
00082 if (mWidth > MAX_IMAGE_SIZE
00083 || mHeight > MAX_IMAGE_SIZE
00084 || mDataSize > (S32)MAX_IMAGE_DATA_SIZE
00085 || mComponents > (S8)MAX_IMAGE_COMPONENTS
00086 )
00087 {
00088 llerrs << "Failed LLImageBase::sanityCheck "
00089 << "width " << mWidth
00090 << "height " << mHeight
00091 << "datasize " << mDataSize
00092 << "components " << mComponents
00093 << "data " << mData
00094 << llendl;
00095 }
00096 }
00097
00098 LLString LLImageBase::sLastErrorMessage;
00099 BOOL LLImageBase::sSizeOverride = FALSE;
00100
00101 BOOL LLImageBase::setLastError(const LLString& message, const LLString& filename)
00102 {
00103 sLastErrorMessage = message;
00104 if (filename != "")
00105 {
00106 sLastErrorMessage += LLString(" FILE:");
00107 sLastErrorMessage += filename;
00108 }
00109 llwarns << sLastErrorMessage << llendl;
00110 return FALSE;
00111 }
00112
00113
00114 void LLImageBase::deleteData()
00115 {
00116 delete[] mData;
00117 mData = NULL;
00118 mDataSize = 0;
00119 }
00120
00121
00122 U8* LLImageBase::allocateData(S32 size)
00123 {
00124 LLMemType mt1((LLMemType::EMemType)mMemType);
00125
00126 if (size < 0)
00127 {
00128 size = mWidth * mHeight * mComponents;
00129 if (size <= 0)
00130 {
00131 llerrs << llformat("LLImageBase::allocateData called with bad dimentions: %dx%dx%d",mWidth,mHeight,mComponents) << llendl;
00132 }
00133 }
00134 else if (size <= 0 || (size > 4096*4096*16 && sSizeOverride == FALSE))
00135 {
00136 llerrs << "LLImageBase::allocateData: bad size: " << size << llendl;
00137 }
00138
00139 resetLastError();
00140
00141 if (!mData || size != mDataSize)
00142 {
00143 deleteData();
00144 mData = new U8[size];
00145 if (!mData)
00146 {
00147 llerrs << "allocate image data: " << size << llendl;
00148 }
00149 mDataSize = size;
00150 }
00151
00152 return mData;
00153 }
00154
00155
00156 U8* LLImageBase::reallocateData(S32 size)
00157 {
00158 LLMemType mt1((LLMemType::EMemType)mMemType);
00159 U8 *new_datap = new U8[size];
00160 if (!new_datap)
00161 {
00162 llwarns << "Out of memory in LLImageBase::reallocateData" << llendl;
00163 return 0;
00164 }
00165 if (mData)
00166 {
00167 S32 bytes = llmin(mDataSize, size);
00168 memcpy(new_datap, mData, bytes);
00169 delete[] mData;
00170 }
00171 mData = new_datap;
00172 mDataSize = size;
00173 return mData;
00174 }
00175
00176
00177 void LLImageBase::setSize(S32 width, S32 height, S32 ncomponents)
00178 {
00179 mWidth = width;
00180 mHeight = height;
00181 mComponents = ncomponents;
00182 }
00183
00184 U8* LLImageBase::allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 size)
00185 {
00186 setSize(width, height, ncomponents);
00187 return allocateData(size);
00188 }
00189
00190
00191
00192
00193
00194 S32 LLImageRaw::sGlobalRawMemory = 0;
00195 S32 LLImageRaw::sRawImageCount = 0;
00196
00197 LLImageRaw::LLImageRaw()
00198 : LLImageBase()
00199 {
00200 mMemType = LLMemType::MTYPE_IMAGERAW;
00201 ++sRawImageCount;
00202 }
00203
00204 LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components)
00205 : LLImageBase()
00206 {
00207 mMemType = LLMemType::MTYPE_IMAGERAW;
00208 llassert( S32(width) * S32(height) * S32(components) <= MAX_IMAGE_DATA_SIZE );
00209 allocateDataSize(width, height, components);
00210 ++sRawImageCount;
00211 }
00212
00213 LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components)
00214 : LLImageBase()
00215 {
00216 mMemType = LLMemType::MTYPE_IMAGERAW;
00217 allocateDataSize(width, height, components);
00218 memcpy(getData(), data, width*height*components);
00219 ++sRawImageCount;
00220 }
00221
00222 LLImageRaw::LLImageRaw(const LLString &filename, bool j2c_lowest_mip_only)
00223 : LLImageBase()
00224 {
00225 createFromFile(filename, j2c_lowest_mip_only);
00226 }
00227
00228 LLImageRaw::~LLImageRaw()
00229 {
00230
00231
00232 deleteData();
00233 --sRawImageCount;
00234 }
00235
00236
00237 U8* LLImageRaw::allocateData(S32 size)
00238 {
00239 U8* res = LLImageBase::allocateData(size);
00240 sGlobalRawMemory += getDataSize();
00241 return res;
00242 }
00243
00244
00245 U8* LLImageRaw::reallocateData(S32 size)
00246 {
00247 sGlobalRawMemory -= getDataSize();
00248 U8* res = LLImageBase::reallocateData(size);
00249 sGlobalRawMemory += getDataSize();
00250 return res;
00251 }
00252
00253
00254 void LLImageRaw::deleteData()
00255 {
00256 sGlobalRawMemory -= getDataSize();
00257 LLImageBase::deleteData();
00258 }
00259
00260 BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
00261 {
00262 if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components))
00263 {
00264 return TRUE;
00265 }
00266
00267 deleteData();
00268
00269 allocateDataSize(width,height,components);
00270
00271 return TRUE;
00272 }
00273
00274 U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const
00275 {
00276 LLMemType mt1((LLMemType::EMemType)mMemType);
00277 U8 *data = new U8[width*height*getComponents()];
00278
00279
00280 if (!data)
00281 {
00282 llerrs << "Out of memory in LLImageRaw::getSubImage" << llendl;
00283 return NULL;
00284 }
00285
00286 U32 i;
00287 for (i = y_pos; i < y_pos+height; i++)
00288 {
00289 memcpy(data + i*width*getComponents(),
00290 getData() + ((y_pos + i)*getWidth() + x_pos)*getComponents(), getComponents()*width);
00291 }
00292 return data;
00293 }
00294
00295 BOOL LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
00296 const U8 *data, U32 stride, BOOL reverse_y)
00297 {
00298 if (!getData())
00299 {
00300 return FALSE;
00301 }
00302 if (!data)
00303 {
00304 return FALSE;
00305 }
00306
00307
00308
00309 U32 i;
00310 for (i = 0; i < height; i++)
00311 {
00312 const U32 row = reverse_y ? height - 1 - i : i;
00313 const U32 from_offset = row * ((stride == 0) ? width*getComponents() : stride);
00314 const U32 to_offset = (y_pos + i)*getWidth() + x_pos;
00315 memcpy(getData() + to_offset*getComponents(),
00316 data + from_offset, getComponents()*width);
00317 }
00318
00319 return TRUE;
00320 }
00321
00322 void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a)
00323 {
00324 llassert( getComponents() <= 4 );
00325
00326 U8 *pos = getData();
00327 U32 x, y;
00328 for (x = 0; x < getWidth(); x++)
00329 {
00330 for (y = 0; y < getHeight(); y++)
00331 {
00332 *pos = r;
00333 pos++;
00334 if (getComponents() == 1)
00335 {
00336 continue;
00337 }
00338 *pos = g;
00339 pos++;
00340 if (getComponents() == 2)
00341 {
00342 continue;
00343 }
00344 *pos = b;
00345 pos++;
00346 if (getComponents() == 3)
00347 {
00348 continue;
00349 }
00350 *pos = a;
00351 pos++;
00352 }
00353 }
00354 }
00355
00356
00357 void LLImageRaw::verticalFlip()
00358 {
00359 LLMemType mt1((LLMemType::EMemType)mMemType);
00360 S32 row_bytes = getWidth() * getComponents();
00361 U8* line_buffer = new U8[row_bytes];
00362 if (!line_buffer )
00363 {
00364 llerrs << "Out of memory in LLImageRaw::verticalFlip()" << llendl;
00365 return;
00366 }
00367 S32 mid_row = getHeight() / 2;
00368 for( S32 row = 0; row < mid_row; row++ )
00369 {
00370 U8* row_a_data = getData() + row * row_bytes;
00371 U8* row_b_data = getData() + (getHeight() - 1 - row) * row_bytes;
00372 memcpy( line_buffer, row_a_data, row_bytes );
00373 memcpy( row_a_data, row_b_data, row_bytes );
00374 memcpy( row_b_data, line_buffer, row_bytes );
00375 }
00376 delete[] line_buffer;
00377 }
00378
00379
00380 void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image)
00381 {
00382
00383 S32 new_width = MIN_IMAGE_SIZE;
00384 S32 new_height = MIN_IMAGE_SIZE;
00385
00386 while( (new_width < getWidth()) && (new_width < max_dim) )
00387 {
00388 new_width <<= 1;
00389 }
00390
00391 while( (new_height < getHeight()) && (new_height < max_dim) )
00392 {
00393 new_height <<= 1;
00394 }
00395
00396 scale( new_width, new_height, scale_image );
00397 }
00398
00399 void LLImageRaw::contractToPowerOfTwo(S32 max_dim, BOOL scale_image)
00400 {
00401
00402 S32 new_width = max_dim;
00403 S32 new_height = max_dim;
00404
00405 while( (new_width > getWidth()) && (new_width > MIN_IMAGE_SIZE) )
00406 {
00407 new_width >>= 1;
00408 }
00409
00410 while( (new_height > getHeight()) && (new_height > MIN_IMAGE_SIZE) )
00411 {
00412 new_height >>= 1;
00413 }
00414
00415 scale( new_width, new_height, scale_image );
00416 }
00417
00418 void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim)
00419 {
00420
00421
00422 const F32 THRESHOLD = 1.75f;
00423
00424
00425 S32 larger_w = max_dim;
00426 S32 smaller_w = max_dim;
00427 while( (smaller_w > getWidth()) && (smaller_w > MIN_IMAGE_SIZE) )
00428 {
00429 larger_w = smaller_w;
00430 smaller_w >>= 1;
00431 }
00432 S32 new_width = ( (F32)getWidth() / smaller_w > THRESHOLD ) ? larger_w : smaller_w;
00433
00434
00435 S32 larger_h = max_dim;
00436 S32 smaller_h = max_dim;
00437 while( (smaller_h > getHeight()) && (smaller_h > MIN_IMAGE_SIZE) )
00438 {
00439 larger_h = smaller_h;
00440 smaller_h >>= 1;
00441 }
00442 S32 new_height = ( (F32)getHeight() / smaller_h > THRESHOLD ) ? larger_h : smaller_h;
00443
00444
00445 scale( new_width, new_height );
00446 }
00447
00448
00449
00450
00451
00452 inline U8 LLImageRaw::fastFractionalMult( U8 a, U8 b )
00453 {
00454 U32 i = a * b + 128;
00455 return U8((i + (i>>8)) >> 8);
00456 }
00457
00458
00459 void LLImageRaw::composite( LLImageRaw* src )
00460 {
00461 LLImageRaw* dst = this;
00462
00463 llassert( (3 == src->getComponents()) || (4 == src->getComponents()) );
00464 llassert( (3 == dst->getComponents()) || (4 == dst->getComponents()) );
00465
00466 if( 3 == dst->getComponents() )
00467 {
00468 if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) )
00469 {
00470
00471 if( 3 == src->getComponents() )
00472 {
00473 copyUnscaled( src );
00474 }
00475 else
00476 {
00477 compositeUnscaled4onto3( src );
00478 }
00479 }
00480 else
00481 {
00482 if( 3 == src->getComponents() )
00483 {
00484 copyScaled( src );
00485 }
00486 else
00487 {
00488 compositeScaled4onto3( src );
00489 }
00490 }
00491 }
00492 else
00493 {
00494
00495 llassert(0);
00496 }
00497 }
00498
00499
00500 void LLImageRaw::compositeScaled4onto3(LLImageRaw* src)
00501 {
00502 LLMemType mt1((LLMemType::EMemType)mMemType);
00503 llinfos << "compositeScaled4onto3" << llendl;
00504
00505 LLImageRaw* dst = this;
00506
00507 llassert( (4 == src->getComponents()) && (3 == dst->getComponents()) );
00508
00509
00510 S32 temp_data_size = src->getWidth() * dst->getHeight() * src->getComponents();
00511 U8* temp_buffer = new U8[ temp_data_size ];
00512 for( S32 col = 0; col < src->getWidth(); col++ )
00513 {
00514 copyLineScaled( src->getData() + (src->getComponents() * col), temp_buffer + (src->getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() );
00515 }
00516
00517
00518 for( S32 row = 0; row < dst->getHeight(); row++ )
00519 {
00520 compositeRowScaled4onto3( temp_buffer + (src->getComponents() * src->getWidth() * row), dst->getData() + (dst->getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth() );
00521 }
00522
00523
00524 delete[] temp_buffer;
00525 }
00526
00527
00528
00529 void LLImageRaw::compositeUnscaled4onto3( LLImageRaw* src )
00530 {
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546 LLImageRaw* dst = this;
00547
00548 llassert( (3 == src->getComponents()) || (4 == src->getComponents()) );
00549 llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
00550
00551
00552 U8* src_data = src->getData();
00553 U8* dst_data = dst->getData();
00554 S32 pixels = getWidth() * getHeight();
00555 while( pixels-- )
00556 {
00557 U8 alpha = src_data[3];
00558 if( alpha )
00559 {
00560 if( 255 == alpha )
00561 {
00562 dst_data[0] = src_data[0];
00563 dst_data[1] = src_data[1];
00564 dst_data[2] = src_data[2];
00565 }
00566 else
00567 {
00568
00569 U8 transparency = 255 - alpha;
00570 dst_data[0] = fastFractionalMult( dst_data[0], transparency ) + fastFractionalMult( src_data[0], alpha );
00571 dst_data[1] = fastFractionalMult( dst_data[1], transparency ) + fastFractionalMult( src_data[1], alpha );
00572 dst_data[2] = fastFractionalMult( dst_data[2], transparency ) + fastFractionalMult( src_data[2], alpha );
00573 }
00574 }
00575
00576 src_data += 4;
00577 dst_data += 3;
00578 }
00579 }
00580
00581
00582 void LLImageRaw::fill( const LLColor4U& color )
00583 {
00584 S32 pixels = getWidth() * getHeight();
00585 if( 4 == getComponents() )
00586 {
00587 U32* data = (U32*) getData();
00588 for( S32 i = 0; i < pixels; i++ )
00589 {
00590 data[i] = color.mAll;
00591 }
00592 }
00593 else
00594 if( 3 == getComponents() )
00595 {
00596 U8* data = getData();
00597 for( S32 i = 0; i < pixels; i++ )
00598 {
00599 data[0] = color.mV[0];
00600 data[1] = color.mV[1];
00601 data[2] = color.mV[2];
00602 data += 3;
00603 }
00604 }
00605 }
00606
00607
00608
00609
00610
00611 void LLImageRaw::copy(LLImageRaw* src)
00612 {
00613 LLImageRaw* dst = this;
00614
00615 llassert( (3 == src->getComponents()) || (4 == src->getComponents()) );
00616 llassert( (3 == dst->getComponents()) || (4 == dst->getComponents()) );
00617
00618 if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) )
00619 {
00620
00621 if( src->getComponents() == dst->getComponents() )
00622 {
00623 copyUnscaled( src );
00624 }
00625 else
00626 if( 3 == src->getComponents() )
00627 {
00628 copyUnscaled3onto4( src );
00629 }
00630 else
00631 {
00632
00633 copyUnscaled4onto3( src );
00634 }
00635 }
00636 else
00637 {
00638
00639
00640 if( src->getComponents() == dst->getComponents() )
00641 {
00642 copyScaled( src );
00643 }
00644 else
00645 if( 3 == src->getComponents() )
00646 {
00647 copyScaled3onto4( src );
00648 }
00649 else
00650 {
00651
00652 copyScaled4onto3( src );
00653 }
00654 }
00655 }
00656
00657
00658 void LLImageRaw::copyUnscaled(LLImageRaw* src)
00659 {
00660 LLImageRaw* dst = this;
00661
00662 llassert( (3 == src->getComponents()) || (4 == src->getComponents()) );
00663 llassert( src->getComponents() == dst->getComponents() );
00664 llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
00665
00666 memcpy( dst->getData(), src->getData(), getWidth() * getHeight() * getComponents() );
00667 }
00668
00669
00670
00671 void LLImageRaw::copyScaled3onto4(LLImageRaw* src)
00672 {
00673 llassert( (3 == src->getComponents()) && (4 == getComponents()) );
00674
00675
00676 LLImageRaw temp( src->getWidth(), src->getHeight(), 4);
00677 temp.copyUnscaled3onto4( src );
00678 copyScaled( &temp );
00679 }
00680
00681
00682
00683 void LLImageRaw::copyScaled4onto3(LLImageRaw* src)
00684 {
00685 llassert( (4 == src->getComponents()) && (3 == getComponents()) );
00686
00687
00688 LLImageRaw temp( src->getWidth(), src->getHeight(), 3);
00689 temp.copyUnscaled4onto3( src );
00690 copyScaled( &temp );
00691 }
00692
00693
00694
00695 void LLImageRaw::copyUnscaled4onto3( LLImageRaw* src )
00696 {
00697 LLImageRaw* dst = this;
00698
00699 llassert( (3 == dst->getComponents()) && (4 == src->getComponents()) );
00700 llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
00701
00702 S32 pixels = getWidth() * getHeight();
00703 U8* src_data = src->getData();
00704 U8* dst_data = dst->getData();
00705 for( S32 i=0; i<pixels; i++ )
00706 {
00707 dst_data[0] = src_data[0];
00708 dst_data[1] = src_data[1];
00709 dst_data[2] = src_data[2];
00710 src_data += 4;
00711 dst_data += 3;
00712 }
00713 }
00714
00715
00716
00717 void LLImageRaw::copyUnscaled3onto4( LLImageRaw* src )
00718 {
00719 LLImageRaw* dst = this;
00720 llassert( 3 == src->getComponents() );
00721 llassert( 4 == dst->getComponents() );
00722 llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
00723
00724 S32 pixels = getWidth() * getHeight();
00725 U8* src_data = src->getData();
00726 U8* dst_data = dst->getData();
00727 for( S32 i=0; i<pixels; i++ )
00728 {
00729 dst_data[0] = src_data[0];
00730 dst_data[1] = src_data[1];
00731 dst_data[2] = src_data[2];
00732 dst_data[3] = 255;
00733 src_data += 3;
00734 dst_data += 4;
00735 }
00736 }
00737
00738
00739
00740 void LLImageRaw::copyScaled( LLImageRaw* src )
00741 {
00742 LLMemType mt1((LLMemType::EMemType)mMemType);
00743 LLImageRaw* dst = this;
00744
00745 llassert( (3 == src->getComponents()) || (4 == src->getComponents()) );
00746 llassert( src->getComponents() == dst->getComponents() );
00747
00748 if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) )
00749 {
00750 memcpy( dst->getData(), src->getData(), getWidth() * getHeight() * getComponents() );
00751 return;
00752 }
00753
00754
00755 S32 temp_data_size = src->getWidth() * dst->getHeight() * getComponents();
00756 U8* temp_buffer = new U8[ temp_data_size ];
00757 for( S32 col = 0; col < src->getWidth(); col++ )
00758 {
00759 copyLineScaled( src->getData() + (getComponents() * col), temp_buffer + (getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() );
00760 }
00761
00762
00763 for( S32 row = 0; row < dst->getHeight(); row++ )
00764 {
00765 copyLineScaled( temp_buffer + (getComponents() * src->getWidth() * row), dst->getData() + (getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth(), 1, 1 );
00766 }
00767
00768
00769 delete[] temp_buffer;
00770 }
00771
00772
00773 void LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
00774 {
00775 LLMemType mt1((LLMemType::EMemType)mMemType);
00776 llassert( (3 == getComponents()) || (4 == getComponents()) );
00777
00778 S32 old_width = getWidth();
00779 S32 old_height = getHeight();
00780
00781 if( (old_width == new_width) && (old_height == new_height) )
00782 {
00783 return;
00784 }
00785
00786
00787
00788 if (scale_image_data)
00789 {
00790
00791 S32 temp_data_size = old_width * new_height * getComponents();
00792 U8* temp_buffer = new U8[ temp_data_size ];
00793 for( S32 col = 0; col < old_width; col++ )
00794 {
00795 copyLineScaled( getData() + (getComponents() * col), temp_buffer + (getComponents() * col), old_height, new_height, old_width, old_width );
00796 }
00797
00798 deleteData();
00799
00800 U8* new_buffer = allocateDataSize(new_width, new_height, getComponents());
00801
00802
00803 for( S32 row = 0; row < new_height; row++ )
00804 {
00805 copyLineScaled( temp_buffer + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 );
00806 }
00807
00808
00809 delete[] temp_buffer;
00810 }
00811 else
00812 {
00813
00814 S32 temp_data_size = old_width * old_height * getComponents();
00815 U8* temp_buffer = new U8[ temp_data_size ];
00816 if (!temp_buffer)
00817 {
00818 llerrs << "Out of memory in LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )" << llendl;
00819 return;
00820 }
00821 memcpy(temp_buffer, getData(), temp_data_size);
00822
00823
00824 U8* new_buffer = allocateDataSize(new_width, new_height, getComponents());
00825
00826 for( S32 row = 0; row < new_height; row++ )
00827 {
00828 if (row < old_height)
00829 {
00830 memcpy(new_buffer + (new_width * row * getComponents()), temp_buffer + (old_width * row * getComponents()), getComponents() * llmin(old_width, new_width));
00831 if (old_width < new_width)
00832 {
00833
00834 memset(new_buffer + (getComponents() * ((new_width * row) + old_width)), 0, getComponents() * (new_width - old_width));
00835 }
00836 }
00837 else
00838 {
00839
00840 memset(new_buffer + (new_width * row * getComponents()), 0, new_width * getComponents());
00841 }
00842 }
00843
00844
00845 delete[] temp_buffer;
00846 }
00847 }
00848
00849 void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step )
00850 {
00851 const S32 components = getComponents();
00852 llassert( components >= 1 && components <= 4 );
00853
00854 const F32 ratio = F32(in_pixel_len) / out_pixel_len;
00855 const F32 norm_factor = 1.f / ratio;
00856
00857 S32 goff = components >= 2 ? 1 : 0;
00858 S32 boff = components >= 3 ? 2 : 0;
00859 for( S32 x = 0; x < out_pixel_len; x++ )
00860 {
00861
00862
00863 const F32 sample0 = x * ratio;
00864 const F32 sample1 = (x+1) * ratio;
00865 const S32 index0 = llfloor(sample0);
00866 const S32 index1 = llfloor(sample1);
00867 const F32 fract0 = 1.f - (sample0 - F32(index0));
00868 const F32 fract1 = sample1 - F32(index1);
00869
00870 if( index0 == index1 )
00871 {
00872
00873 S32 t0 = x * out_pixel_step * components;
00874 S32 t1 = index0 * in_pixel_step * components;
00875 U8* outp = out + t0;
00876 U8* inp = in + t1;
00877 for (S32 i = 0; i < components; ++i)
00878 {
00879 *outp = *inp;
00880 ++outp;
00881 ++inp;
00882 }
00883 }
00884 else
00885 {
00886
00887 S32 t1 = index0 * in_pixel_step * components;
00888 F32 r = in[t1 + 0] * fract0;
00889 F32 g = in[t1 + goff] * fract0;
00890 F32 b = in[t1 + boff] * fract0;
00891 F32 a = 0;
00892 if( components == 4)
00893 {
00894 a = in[t1 + 3] * fract0;
00895 }
00896
00897
00898 if (components < 4)
00899 {
00900 for( S32 u = index0 + 1; u < index1; u++ )
00901 {
00902 S32 t2 = u * in_pixel_step * components;
00903 r += in[t2 + 0];
00904 g += in[t2 + goff];
00905 b += in[t2 + boff];
00906 }
00907 }
00908 else
00909 {
00910 for( S32 u = index0 + 1; u < index1; u++ )
00911 {
00912 S32 t2 = u * in_pixel_step * components;
00913 r += in[t2 + 0];
00914 g += in[t2 + 1];
00915 b += in[t2 + 2];
00916 a += in[t2 + 3];
00917 }
00918 }
00919
00920
00921
00922 if( fract1 && index1 < in_pixel_len )
00923 {
00924 S32 t3 = index1 * in_pixel_step * components;
00925 if (components < 4)
00926 {
00927 U8 in0 = in[t3 + 0];
00928 U8 in1 = in[t3 + goff];
00929 U8 in2 = in[t3 + boff];
00930 r += in0 * fract1;
00931 g += in1 * fract1;
00932 b += in2 * fract1;
00933 }
00934 else
00935 {
00936 U8 in0 = in[t3 + 0];
00937 U8 in1 = in[t3 + 1];
00938 U8 in2 = in[t3 + 2];
00939 U8 in3 = in[t3 + 3];
00940 r += in0 * fract1;
00941 g += in1 * fract1;
00942 b += in2 * fract1;
00943 a += in3 * fract1;
00944 }
00945 }
00946
00947 r *= norm_factor;
00948 g *= norm_factor;
00949 b *= norm_factor;
00950 a *= norm_factor;
00951
00952 S32 t4 = x * out_pixel_step * components;
00953 out[t4 + 0] = U8(llround(r));
00954 if (components >= 2)
00955 out[t4 + 1] = U8(llround(g));
00956 if (components >= 3)
00957 out[t4 + 2] = U8(llround(b));
00958 if( components == 4)
00959 out[t4 + 3] = U8(llround(a));
00960 }
00961 }
00962 }
00963
00964 void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len )
00965 {
00966 llassert( getComponents() == 3 );
00967
00968 const S32 IN_COMPONENTS = 4;
00969 const S32 OUT_COMPONENTS = 3;
00970
00971 const F32 ratio = F32(in_pixel_len) / out_pixel_len;
00972 const F32 norm_factor = 1.f / ratio;
00973
00974 for( S32 x = 0; x < out_pixel_len; x++ )
00975 {
00976
00977
00978 const F32 sample0 = x * ratio;
00979 const F32 sample1 = (x+1) * ratio;
00980 const S32 index0 = S32(sample0);
00981 const S32 index1 = S32(sample1);
00982 const F32 fract0 = 1.f - (sample0 - F32(index0));
00983 const F32 fract1 = sample1 - F32(index1);
00984
00985 U8 in_scaled_r;
00986 U8 in_scaled_g;
00987 U8 in_scaled_b;
00988 U8 in_scaled_a;
00989
00990 if( index0 == index1 )
00991 {
00992
00993 S32 t1 = index0 * IN_COMPONENTS;
00994 in_scaled_r = in[t1 + 0];
00995 in_scaled_g = in[t1 + 0];
00996 in_scaled_b = in[t1 + 0];
00997 in_scaled_a = in[t1 + 0];
00998 }
00999 else
01000 {
01001
01002 S32 t1 = index0 * IN_COMPONENTS;
01003 F32 r = in[t1 + 0] * fract0;
01004 F32 g = in[t1 + 1] * fract0;
01005 F32 b = in[t1 + 2] * fract0;
01006 F32 a = in[t1 + 3] * fract0;
01007
01008
01009 for( S32 u = index0 + 1; u < index1; u++ )
01010 {
01011 S32 t2 = u * IN_COMPONENTS;
01012 r += in[t2 + 0];
01013 g += in[t2 + 1];
01014 b += in[t2 + 2];
01015 a += in[t2 + 3];
01016 }
01017
01018
01019
01020 if( fract1 && index1 < in_pixel_len )
01021 {
01022 S32 t3 = index1 * IN_COMPONENTS;
01023 r += in[t3 + 0] * fract1;
01024 g += in[t3 + 1] * fract1;
01025 b += in[t3 + 2] * fract1;
01026 a += in[t3 + 3] * fract1;
01027 }
01028
01029 r *= norm_factor;
01030 g *= norm_factor;
01031 b *= norm_factor;
01032 a *= norm_factor;
01033
01034 in_scaled_r = U8(llround(r));
01035 in_scaled_g = U8(llround(g));
01036 in_scaled_b = U8(llround(b));
01037 in_scaled_a = U8(llround(a));
01038 }
01039
01040 if( in_scaled_a )
01041 {
01042 if( 255 == in_scaled_a )
01043 {
01044 out[0] = in_scaled_r;
01045 out[1] = in_scaled_g;
01046 out[2] = in_scaled_b;
01047 }
01048 else
01049 {
01050 U8 transparency = 255 - in_scaled_a;
01051 out[0] = fastFractionalMult( out[0], transparency ) + fastFractionalMult( in_scaled_r, in_scaled_a );
01052 out[1] = fastFractionalMult( out[1], transparency ) + fastFractionalMult( in_scaled_g, in_scaled_a );
01053 out[2] = fastFractionalMult( out[2], transparency ) + fastFractionalMult( in_scaled_b, in_scaled_a );
01054 }
01055 }
01056 out += OUT_COMPONENTS;
01057 }
01058 }
01059
01060
01061
01062
01063 static struct
01064 {
01065 const char* exten;
01066 S8 codec;
01067 }
01068 file_extensions[] =
01069 {
01070 { "bmp", IMG_CODEC_BMP },
01071 { "tga", IMG_CODEC_TGA },
01072 { "j2c", IMG_CODEC_J2C },
01073 { "jp2", IMG_CODEC_J2C },
01074 { "texture", IMG_CODEC_J2C },
01075 { "jpg", IMG_CODEC_JPEG },
01076 { "jpeg", IMG_CODEC_JPEG },
01077 { "mip", IMG_CODEC_DXT },
01078 { "dxt", IMG_CODEC_DXT },
01079 { "png", IMG_CODEC_PNG }
01080 };
01081 #define NUM_FILE_EXTENSIONS sizeof(file_extensions)/sizeof(file_extensions[0])
01082
01083 static LLString find_file(LLString &name, S8 *codec)
01084 {
01085 LLString tname;
01086 for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++)
01087 {
01088 tname = name + "." + LLString(file_extensions[i].exten);
01089 llifstream ifs(tname.c_str(), llifstream::binary);
01090 if (ifs.is_open())
01091 {
01092 ifs.close();
01093 if (codec)
01094 *codec = file_extensions[i].codec;
01095 return LLString(file_extensions[i].exten);
01096 }
01097 }
01098 return LLString("");
01099 }
01100
01101 static S8 get_codec(const LLString& exten)
01102 {
01103 for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++)
01104 {
01105 if (exten == file_extensions[i].exten)
01106 return file_extensions[i].codec;
01107 }
01108 return IMG_CODEC_INVALID;
01109 }
01110
01111 bool LLImageRaw::createFromFile(const LLString &filename, bool j2c_lowest_mip_only)
01112 {
01113 LLString name = filename;
01114 size_t dotidx = name.rfind('.');
01115 S8 codec = IMG_CODEC_INVALID;
01116 LLString exten;
01117
01118 deleteData();
01119
01120 if (dotidx != LLString::npos)
01121 {
01122 exten = name.substr(dotidx+1);
01123 LLString::toLower(exten);
01124 codec = get_codec(exten);
01125 }
01126 else
01127 {
01128 exten = find_file(name, &codec);
01129 name = name + "." + exten;
01130 }
01131 if (codec == IMG_CODEC_INVALID)
01132 {
01133 return false;
01134 }
01135
01136 llifstream ifs(name.c_str(), llifstream::binary);
01137 if (!ifs.is_open())
01138 {
01139
01140 lldebugs << "Unable to open image file: " << name << llendl;
01141 return false;
01142 }
01143
01144 ifs.seekg (0, std::ios::end);
01145 int length = ifs.tellg();
01146 if (j2c_lowest_mip_only && length > 2048)
01147 {
01148 length = 2048;
01149 }
01150 ifs.seekg (0, std::ios::beg);
01151
01152 if (!length)
01153 {
01154 llinfos << "Zero length file file: " << name << llendl;
01155 return false;
01156 }
01157
01158 LLPointer<LLImageFormatted> image;
01159 switch(codec)
01160 {
01161
01162 case IMG_CODEC_BMP:
01163 image = new LLImageBMP();
01164 break;
01165 case IMG_CODEC_TGA:
01166 image = new LLImageTGA();
01167 break;
01168 #if JPEG_SUPPORT
01169 case IMG_CODEC_JPEG:
01170 image = new LLImageJPEG();
01171 break;
01172 #endif
01173 case IMG_CODEC_J2C:
01174 image = new LLImageJ2C();
01175 break;
01176 case IMG_CODEC_DXT:
01177 image = new LLImageDXT();
01178 break;
01179 default:
01180 return false;
01181 }
01182 llassert(image.notNull());
01183
01184 U8 *buffer = image->allocateData(length);
01185 ifs.read ((char*)buffer, length);
01186 ifs.close();
01187
01188 image->updateData();
01189
01190 if (j2c_lowest_mip_only && codec == IMG_CODEC_J2C)
01191 {
01192 S32 width = image->getWidth();
01193 S32 height = image->getHeight();
01194 S32 discard_level = 0;
01195 while (width > 1 && height > 1 && discard_level < MAX_DISCARD_LEVEL)
01196 {
01197 width >>= 1;
01198 height >>= 1;
01199 discard_level++;
01200 }
01201 ((LLImageJ2C *)((LLImageFormatted*)image))->setDiscardLevel(discard_level);
01202 }
01203
01204 BOOL success = image->decode(this, 100000.0f);
01205 image = NULL;
01206
01207 if (!success)
01208 {
01209 deleteData();
01210 llwarns << "Unable to decode image" << name << llendl;
01211 return false;
01212 }
01213
01214 return true;
01215 }
01216
01217
01218
01219
01220
01221
01222 S32 LLImageFormatted::sGlobalFormattedMemory = 0;
01223
01224 LLImageFormatted::LLImageFormatted(S8 codec)
01225 : LLImageBase(),
01226 mCodec(codec),
01227 mDecoding(0),
01228 mDecoded(0),
01229 mDiscardLevel(0)
01230 {
01231 mMemType = LLMemType::MTYPE_IMAGEFORMATTED;
01232 }
01233
01234
01235 LLImageFormatted::~LLImageFormatted()
01236 {
01237
01238
01239 deleteData();
01240 }
01241
01242
01243
01244
01245 LLImageFormatted* LLImageFormatted::createFromType(S8 codec)
01246 {
01247 LLImageFormatted* image;
01248 switch(codec)
01249 {
01250 case IMG_CODEC_BMP:
01251 image = new LLImageBMP();
01252 break;
01253 case IMG_CODEC_TGA:
01254 image = new LLImageTGA();
01255 break;
01256 #if JPEG_SUPPORT
01257 case IMG_CODEC_JPEG:
01258 image = new LLImageJPEG();
01259 break;
01260 #endif
01261 case IMG_CODEC_J2C:
01262 image = new LLImageJ2C();
01263 break;
01264 case IMG_CODEC_DXT:
01265 image = new LLImageDXT();
01266 break;
01267 default:
01268 image = NULL;
01269 break;
01270 }
01271 return image;
01272 }
01273
01274
01275 LLImageFormatted* LLImageFormatted::createFromExtension(const LLString& instring)
01276 {
01277 LLString exten;
01278 size_t dotidx = instring.rfind('.');
01279 if (dotidx != LLString::npos)
01280 {
01281 exten = instring.substr(dotidx+1);
01282 }
01283 else
01284 {
01285 exten = instring;
01286 }
01287 S8 codec = get_codec(exten);
01288 return createFromType(codec);
01289 }
01290
01291
01292
01293 void LLImageFormatted::dump()
01294 {
01295 LLImageBase::dump();
01296
01297 llinfos << "LLImageFormatted"
01298 << " mDecoding " << mDecoding
01299 << " mCodec " << S32(mCodec)
01300 << " mDecoded " << mDecoded
01301 << llendl;
01302 }
01303
01304
01305
01306 S32 LLImageFormatted::calcDataSize(S32 discard_level)
01307 {
01308 if (discard_level < 0)
01309 {
01310 discard_level = mDiscardLevel;
01311 }
01312 S32 w = getWidth() >> discard_level;
01313 S32 h = getHeight() >> discard_level;
01314 w = llmax(w, 1);
01315 h = llmax(h, 1);
01316 return w * h * getComponents();
01317 }
01318
01319 S32 LLImageFormatted::calcDiscardLevelBytes(S32 bytes)
01320 {
01321 llassert(bytes >= 0);
01322 S32 discard_level = 0;
01323 while (1)
01324 {
01325 S32 bytes_needed = calcDataSize(discard_level);
01326 if (bytes_needed <= bytes)
01327 {
01328 break;
01329 }
01330 discard_level++;
01331 if (discard_level > MAX_IMAGE_MIP)
01332 {
01333 return -1;
01334 }
01335 }
01336 return discard_level;
01337 }
01338
01339
01340
01341
01342
01343 BOOL LLImageFormatted::decode(LLImageRaw* raw_image,F32 decode_time, S32 first_channel, S32 max_channel)
01344 {
01345 llassert( (first_channel == 0) && (max_channel == 4) );
01346 return decode( raw_image, decode_time );
01347 }
01348
01349
01350
01351
01352 U8* LLImageFormatted::allocateData(S32 size)
01353 {
01354 U8* res = LLImageBase::allocateData(size);
01355 sGlobalFormattedMemory += getDataSize();
01356 return res;
01357 }
01358
01359
01360 U8* LLImageFormatted::reallocateData(S32 size)
01361 {
01362 sGlobalFormattedMemory -= getDataSize();
01363 U8* res = LLImageBase::reallocateData(size);
01364 sGlobalFormattedMemory += getDataSize();
01365 return res;
01366 }
01367
01368
01369 void LLImageFormatted::deleteData()
01370 {
01371 sGlobalFormattedMemory -= getDataSize();
01372 LLImageBase::deleteData();
01373 }
01374
01375
01376
01377
01378 void LLImageFormatted::sanityCheck()
01379 {
01380 LLImageBase::sanityCheck();
01381
01382 if (mCodec >= IMG_CODEC_EOF)
01383 {
01384 llerrs << "Failed LLImageFormatted::sanityCheck "
01385 << "decoding " << S32(mDecoding)
01386 << "decoded " << S32(mDecoded)
01387 << "codec " << S32(mCodec)
01388 << llendl;
01389 }
01390 }
01391
01392
01393
01394 BOOL LLImageFormatted::copyData(U8 *data, S32 size)
01395 {
01396 if ( data && ((data != getData()) || (size != getDataSize())) )
01397 {
01398 deleteData();
01399 allocateData(size);
01400 memcpy(getData(), data, size);
01401 }
01402 return TRUE;
01403 }
01404
01405
01406 void LLImageFormatted::setData(U8 *data, S32 size)
01407 {
01408 if (data && data != getData())
01409 {
01410 deleteData();
01411 setDataAndSize(data, size);
01412 sGlobalFormattedMemory += getDataSize();
01413 }
01414 }
01415
01416 void LLImageFormatted::appendData(U8 *data, S32 size)
01417 {
01418 if (data)
01419 {
01420 if (!getData())
01421 {
01422 setData(data, size);
01423 }
01424 else
01425 {
01426 S32 cursize = getDataSize();
01427 S32 newsize = cursize + size;
01428 reallocateData(newsize);
01429 memcpy(getData() + cursize, data, size);
01430 }
01431 }
01432 }
01433
01434
01435
01436 BOOL LLImageFormatted::load(const LLString &filename)
01437 {
01438 resetLastError();
01439
01440 S32 file_size = 0;
01441 apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RB, &file_size);
01442 if (!apr_file)
01443 {
01444 setLastError("Unable to open file for reading", filename);
01445 return FALSE;
01446 }
01447 if (file_size == 0)
01448 {
01449 setLastError("File is empty",filename);
01450 apr_file_close(apr_file);
01451 return FALSE;
01452 }
01453
01454 BOOL res;
01455 U8 *data = allocateData(file_size);
01456 apr_size_t bytes_read = file_size;
01457 apr_status_t s = apr_file_read(apr_file, data, &bytes_read);
01458 if (s != APR_SUCCESS || (S32) bytes_read != file_size)
01459 {
01460 deleteData();
01461 setLastError("Unable to read entire file",filename);
01462 res = FALSE;
01463 }
01464 else
01465 {
01466 res = updateData();
01467 }
01468 apr_file_close(apr_file);
01469
01470 return res;
01471 }
01472
01473 BOOL LLImageFormatted::save(const LLString &filename)
01474 {
01475 resetLastError();
01476
01477 apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_WB);
01478 if (!apr_file)
01479 {
01480 setLastError("Unable to open file for reading", filename);
01481 return FALSE;
01482 }
01483
01484 ll_apr_file_write(apr_file, getData(), getDataSize());
01485 apr_file_close(apr_file);
01486
01487 return TRUE;
01488 }
01489
01490
01491
01492
01493
01494
01495
01496
01497 S8 LLImageFormatted::getCodec() const
01498 {
01499 return mCodec;
01500 }
01501
01502
01503
01504 static void avg4_colors4(const U8* a, const U8* b, const U8* c, const U8* d, U8* dst)
01505 {
01506 dst[0] = (U8)(((U32)(a[0]) + b[0] + c[0] + d[0])>>2);
01507 dst[1] = (U8)(((U32)(a[1]) + b[1] + c[1] + d[1])>>2);
01508 dst[2] = (U8)(((U32)(a[2]) + b[2] + c[2] + d[2])>>2);
01509 dst[3] = (U8)(((U32)(a[3]) + b[3] + c[3] + d[3])>>2);
01510 }
01511
01512 static void avg4_colors3(const U8* a, const U8* b, const U8* c, const U8* d, U8* dst)
01513 {
01514 dst[0] = (U8)(((U32)(a[0]) + b[0] + c[0] + d[0])>>2);
01515 dst[1] = (U8)(((U32)(a[1]) + b[1] + c[1] + d[1])>>2);
01516 dst[2] = (U8)(((U32)(a[2]) + b[2] + c[2] + d[2])>>2);
01517 }
01518
01519 static void avg4_colors2(const U8* a, const U8* b, const U8* c, const U8* d, U8* dst)
01520 {
01521 dst[0] = (U8)(((U32)(a[0]) + b[0] + c[0] + d[0])>>2);
01522 dst[1] = (U8)(((U32)(a[1]) + b[1] + c[1] + d[1])>>2);
01523 }
01524
01525
01526 void LLImageBase::generateMip(const U8* indata, U8* mipdata, S32 width, S32 height, S32 nchannels)
01527 {
01528 llassert(width > 0 && height > 0);
01529 U8* data = mipdata;
01530 S32 in_width = width*2;
01531 for (S32 h=0; h<height; h++)
01532 {
01533 for (S32 w=0; w<width; w++)
01534 {
01535 switch(nchannels)
01536 {
01537 case 4:
01538 avg4_colors4(indata, indata+4, indata+4*in_width, indata+4*in_width+4, data);
01539 break;
01540 case 3:
01541 avg4_colors3(indata, indata+3, indata+3*in_width, indata+3*in_width+3, data);
01542 break;
01543 case 2:
01544 avg4_colors2(indata, indata+2, indata+2*in_width, indata+2*in_width+2, data);
01545 break;
01546 case 1:
01547 *(U8*)data = (U8)(((U32)(indata[0]) + indata[1] + indata[in_width] + indata[in_width+1])>>2);
01548 break;
01549 default:
01550 llerrs << "generateMmip called with bad num channels" << llendl;
01551 }
01552 indata += nchannels*2;
01553 data += nchannels;
01554 }
01555 indata += nchannels*in_width;
01556 }
01557 }
01558
01559
01560
01561
01562
01563 F32 LLImageBase::calc_download_priority(F32 virtual_size, F32 visible_pixels, S32 bytes_sent)
01564 {
01565 F32 w_priority;
01566
01567 F32 bytes_weight = 1.f;
01568 if (!bytes_sent)
01569 {
01570 bytes_weight = 20.f;
01571 }
01572 else if (bytes_sent < 1000)
01573 {
01574 bytes_weight = 1.f;
01575 }
01576 else if (bytes_sent < 2000)
01577 {
01578 bytes_weight = 1.f/1.5f;
01579 }
01580 else if (bytes_sent < 4000)
01581 {
01582 bytes_weight = 1.f/3.f;
01583 }
01584 else if (bytes_sent < 8000)
01585 {
01586 bytes_weight = 1.f/6.f;
01587 }
01588 else if (bytes_sent < 16000)
01589 {
01590 bytes_weight = 1.f/12.f;
01591 }
01592 else if (bytes_sent < 32000)
01593 {
01594 bytes_weight = 1.f/20.f;
01595 }
01596 else if (bytes_sent < 64000)
01597 {
01598 bytes_weight = 1.f/32.f;
01599 }
01600 else
01601 {
01602 bytes_weight = 1.f/64.f;
01603 }
01604 bytes_weight *= bytes_weight;
01605
01606
01607
01608 F32 virtual_size_factor = virtual_size / (10.f*10.f);
01609
01610
01611
01612
01613
01614
01615 w_priority = (F32)log10(bytes_weight * virtual_size_factor);
01616
01617
01618
01619
01620
01621 if (w_priority > 0.f)
01622 {
01623 F32 pixel_weight = (F32)log10(visible_pixels + 1)*3.0f;
01624 w_priority *= pixel_weight;
01625 }
01626
01627 return w_priority;
01628 }
01629
01630