llimage.cpp

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

Generated on Fri May 16 08:32:10 2008 for SecondLife by  doxygen 1.5.5