llimagedxt.cpp

Go to the documentation of this file.
00001 
00031 #include "linden_common.h"
00032 
00033 #include "llimagedxt.h"
00034 
00035 //static
00036 void LLImageDXT::checkMinWidthHeight(EFileFormat format, S32& width, S32& height)
00037 {
00038         S32 mindim = (format >= FORMAT_DXT1 && format <= FORMAT_DXR5) ? 4 : 1;
00039         width = llmax(width, mindim);
00040         height = llmax(height, mindim);
00041 }
00042 
00043 //static
00044 S32 LLImageDXT::formatBits(EFileFormat format)
00045 {
00046         switch (format)
00047         {
00048           case FORMAT_DXT1:     return 4;
00049           case FORMAT_DXR1:     return 4;
00050           case FORMAT_I8:               return 8;
00051           case FORMAT_A8:               return 8;
00052           case FORMAT_DXT3:             return 8;
00053           case FORMAT_DXR3:             return 8;
00054           case FORMAT_DXR5:             return 8;
00055           case FORMAT_DXT5:             return 8;
00056           case FORMAT_RGB8:             return 24;
00057           case FORMAT_RGBA8:    return 32;
00058           default:
00059                 llerrs << "LLImageDXT::Unknown format: " << format << llendl;
00060                 return 0;
00061         }
00062 };
00063 
00064 //static
00065 S32 LLImageDXT::formatBytes(EFileFormat format, S32 width, S32 height)
00066 {
00067         checkMinWidthHeight(format, width, height);
00068         S32 bytes = ((width*height*formatBits(format)+7)>>3);
00069         S32 aligned = (bytes+3)&~3;
00070         return aligned;
00071 }
00072 
00073 //static
00074 S32 LLImageDXT::formatComponents(EFileFormat format)
00075 {
00076         switch (format)
00077         {
00078           case FORMAT_DXT1:     return 3;
00079           case FORMAT_DXR1:     return 3;
00080           case FORMAT_I8:               return 1;
00081           case FORMAT_A8:               return 1;
00082           case FORMAT_DXT3:             return 4;
00083           case FORMAT_DXR3:             return 4;
00084           case FORMAT_DXT5:             return 4;
00085           case FORMAT_DXR5:             return 4;
00086           case FORMAT_RGB8:             return 3;
00087           case FORMAT_RGBA8:    return 4;
00088           default:
00089                 llerrs << "LLImageDXT::Unknown format: " << format << llendl;
00090                 return 0;
00091         }
00092 };
00093 
00094 // static 
00095 LLImageDXT::EFileFormat LLImageDXT::getFormat(S32 fourcc)
00096 {
00097         switch(fourcc)
00098         {
00099                 case 0x20203849: return FORMAT_I8;
00100                 case 0x20203841: return FORMAT_A8;
00101                 case 0x20424752: return FORMAT_RGB8;
00102                 case 0x41424752: return FORMAT_RGBA8;
00103                 case 0x31525844: return FORMAT_DXR1;
00104                 case 0x32525844: return FORMAT_DXR2;
00105                 case 0x33525844: return FORMAT_DXR3;
00106                 case 0x34525844: return FORMAT_DXR4;
00107                 case 0x35525844: return FORMAT_DXR5;
00108                 case 0x31545844: return FORMAT_DXT1;
00109                 case 0x32545844: return FORMAT_DXT2;
00110                 case 0x33545844: return FORMAT_DXT3;
00111                 case 0x34545844: return FORMAT_DXT4;
00112                 case 0x35545844: return FORMAT_DXT5;
00113                 default: return FORMAT_UNKNOWN;
00114         }
00115 }
00116 
00117 //static
00118 S32 LLImageDXT::getFourCC(EFileFormat format)
00119 {
00120         switch(format)
00121         {
00122                 case FORMAT_I8: return 0x20203849;
00123                 case FORMAT_A8: return 0x20203841;
00124                 case FORMAT_RGB8: return 0x20424752;
00125                 case FORMAT_RGBA8: return 0x41424752;
00126                 case FORMAT_DXR1: return 0x31525844;
00127                 case FORMAT_DXR2: return 0x32525844;
00128                 case FORMAT_DXR3: return 0x33525844;
00129                 case FORMAT_DXR4: return 0x34525844;
00130                 case FORMAT_DXR5: return 0x35525844;
00131                 case FORMAT_DXT1: return 0x31545844;
00132                 case FORMAT_DXT2: return 0x32545844;
00133                 case FORMAT_DXT3: return 0x33545844;
00134                 case FORMAT_DXT4: return 0x34545844;
00135                 case FORMAT_DXT5: return 0x35545844;
00136                 default: return 0x00000000;
00137         }
00138 }
00139 
00140 //static
00141 void LLImageDXT::calcDiscardWidthHeight(S32 discard_level, EFileFormat format, S32& width, S32& height)
00142 {
00143         while (discard_level > 0 && width > 1 && height > 1)
00144         {
00145                 discard_level--;
00146                 width >>= 1;
00147                 height >>= 1;
00148         }
00149         checkMinWidthHeight(format, width, height);
00150 }
00151 
00152 //static
00153 S32 LLImageDXT::calcNumMips(S32 width, S32 height)
00154 {
00155         S32 nmips = 0;
00156         while (width > 0 && height > 0)
00157         {
00158                 width >>= 1;
00159                 height >>= 1;
00160                 nmips++;
00161         }
00162         return nmips;
00163 }
00164 
00165 //============================================================================
00166 
00167 LLImageDXT::LLImageDXT()
00168         : LLImageFormatted(IMG_CODEC_DXT),
00169           mFileFormat(FORMAT_UNKNOWN),
00170           mHeaderSize(0)
00171 {
00172 }
00173 
00174 LLImageDXT::~LLImageDXT()
00175 {
00176 }
00177 
00178 // virtual
00179 BOOL LLImageDXT::updateData()
00180 {
00181         resetLastError();
00182 
00183         U8* data = getData();
00184         S32 data_size = getDataSize();
00185         
00186         if (!data || !data_size)
00187         {
00188                 setLastError("LLImageDXT uninitialized");
00189                 return FALSE;
00190         }
00191 
00192         S32 width, height, miplevelmax;
00193         dxtfile_header_t* header = (dxtfile_header_t*)data;
00194         if (header->fourcc != 0x20534444)
00195         {
00196                 dxtfile_header_old_t* oldheader = (dxtfile_header_old_t*)header;
00197                 mHeaderSize = sizeof(dxtfile_header_old_t);
00198                 mFileFormat = EFileFormat(oldheader->format);
00199                 miplevelmax = llmin(oldheader->maxlevel,MAX_IMAGE_MIP);
00200                 width = oldheader->maxwidth;
00201                 height = oldheader->maxheight;
00202         }
00203         else
00204         {
00205                 mHeaderSize = sizeof(dxtfile_header_t);
00206                 mFileFormat = getFormat(header->pixel_fmt.fourcc);
00207                 miplevelmax = llmin(header->num_mips-1,MAX_IMAGE_MIP);
00208                 width = header->maxwidth;
00209                 height = header->maxheight;
00210         }
00211 
00212         if (data_size < mHeaderSize)
00213         {
00214                 llerrs << "LLImageDXT: not enough data" << llendl;
00215         }
00216         S32 ncomponents = formatComponents(mFileFormat);
00217         setSize(width, height, ncomponents);
00218 
00219         S32 discard = calcDiscardLevelBytes(data_size);
00220         discard = llmin(discard, miplevelmax);
00221         setDiscardLevel(discard);
00222 
00223         return TRUE;
00224 }
00225 
00226 // discard: 0 = largest (last) mip
00227 S32 LLImageDXT::getMipOffset(S32 discard)
00228 {
00229         if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXT5)
00230         {
00231                 llerrs << "getMipOffset called with old (unsupported) format" << llendl;
00232         }
00233         S32 width = getWidth(), height = getHeight();
00234         S32 num_mips = calcNumMips(width, height);
00235         discard = llclamp(discard, 0, num_mips-1);
00236         S32 last_mip = num_mips-1-discard;
00237         llassert(mHeaderSize > 0);
00238         S32 offset = mHeaderSize;
00239         for (S32 mipidx = num_mips-1; mipidx >= 0; mipidx--)
00240         {
00241                 if (mipidx < last_mip)
00242                 {
00243                         offset += formatBytes(mFileFormat, width, height);
00244                 }
00245                 width >>= 1;
00246                 height >>= 1;
00247         }
00248         return offset;
00249 }
00250 
00251 void LLImageDXT::setFormat()
00252 {
00253         S32 ncomponents = getComponents();
00254         switch (ncomponents)
00255         {
00256           case 3: mFileFormat = FORMAT_DXR1; break;
00257           case 4: mFileFormat = FORMAT_DXR3; break;
00258           default: llerrs << "LLImageDXT::setFormat called with ncomponents = " << ncomponents << llendl;
00259         }
00260         mHeaderSize = calcHeaderSize();
00261 }
00262                 
00263 // virtual
00264 BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
00265 {
00266         llassert_always(raw_image);
00267         
00268         if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5)
00269         {
00270                 llwarns << "Attempt to decode compressed LLImageDXT to Raw (unsupported)" << llendl;
00271                 return FALSE;
00272         }
00273         
00274         S32 width = getWidth(), height = getHeight();
00275         S32 ncomponents = getComponents();
00276         S32 image_size = formatBytes(mFileFormat, width, height);
00277         U8* data = getData() + getMipOffset(0);
00278         
00279         if ((!getData()) || (data + image_size > getData() + getDataSize()))
00280         {
00281                 setLastError("LLImageDXT trying to decode an image with not enough data!");
00282                 return FALSE;
00283         }
00284 
00285         raw_image->resize(width, height, ncomponents);
00286         memcpy(raw_image->getData(), data, image_size); /* Flawfinder: ignore */
00287 
00288         return TRUE;
00289 }
00290 
00291 BOOL LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard)
00292 {
00293         if (discard < 0)
00294         {
00295                 discard = mDiscardLevel;
00296         }
00297         else if (discard < mDiscardLevel)
00298         {
00299                 llerrs << "Request for invalid discard level" << llendl;
00300         }
00301         U8* data = getData() + getMipOffset(discard);
00302         // I'm not sure these are the correct initial values for height and width,
00303         // but previously they were being used uninitialized. JC
00304         S32 width = raw->getWidth();
00305         S32 height = raw->getHeight();
00306         calcDiscardWidthHeight(discard, mFileFormat, width, height);
00307         raw = new LLImageRaw(data, width, height, getComponents());
00308         return TRUE;
00309 }
00310 
00311 BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time, bool explicit_mips)
00312 {
00313         llassert_always(raw_image);
00314         
00315         S32 ncomponents = raw_image->getComponents();
00316         EFileFormat format;
00317         switch (ncomponents)
00318         {
00319           case 1:
00320                 format = FORMAT_A8;
00321                 break;
00322           case 3:
00323                 format = FORMAT_RGB8;
00324                 break;
00325           case 4:
00326                 format = FORMAT_RGBA8;
00327                 break;
00328           default:
00329                 llerrs << "LLImageDXT::encode: Unhandled channel number: " << ncomponents << llendl;
00330                 return 0;
00331         }
00332 
00333         S32 width = raw_image->getWidth();
00334         S32 height = raw_image->getHeight();
00335 
00336         if (explicit_mips)
00337         {
00338                 height = (height/3)*2;
00339         }
00340 
00341         setSize(width, height, ncomponents);
00342         mHeaderSize = sizeof(dxtfile_header_t);
00343         mFileFormat = format;
00344 
00345         S32 nmips = calcNumMips(width, height);
00346         S32 w = width;
00347         S32 h = height;
00348 
00349         S32 totbytes = mHeaderSize;
00350         for (S32 mip=0; mip<nmips; mip++)
00351         {
00352                 totbytes += formatBytes(format,w,h);
00353                 w >>= 1;
00354                 h >>= 1;
00355         }
00356 
00357         allocateData(totbytes);
00358 
00359         U8* data = getData();
00360         dxtfile_header_t* header = (dxtfile_header_t*)data;
00361         llassert(mHeaderSize > 0);
00362         memset(header, 0, mHeaderSize);
00363         header->fourcc = 0x20534444;
00364         header->pixel_fmt.fourcc = getFourCC(format);
00365         header->num_mips = nmips;
00366         header->maxwidth = width;
00367         header->maxheight = height;
00368 
00369         U8* prev_mipdata = 0;
00370         w = width, h = height;
00371         for (S32 mip=0; mip<nmips; mip++)
00372         {
00373                 U8* mipdata = data + getMipOffset(mip);
00374                 S32 bytes = formatBytes(format, w, h);
00375                 if (mip==0)
00376                 {
00377                         memcpy(mipdata, raw_image->getData(), bytes);   /* Flawfinder: ignore */
00378                 }
00379                 else if (explicit_mips)
00380                 {
00381                         extractMip(raw_image->getData(), mipdata, width, height, w, h, format);
00382                 }
00383                 else
00384                 {
00385                         generateMip(prev_mipdata, mipdata, w, h, ncomponents);
00386                 }
00387                 w >>= 1;
00388                 h >>= 1;
00389                 checkMinWidthHeight(format, w, h);
00390                 prev_mipdata = mipdata;
00391         }
00392         
00393         return TRUE;
00394 }
00395 
00396 // virtual
00397 BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time)
00398 {
00399         return encode(raw_image, time, false);
00400 }
00401 
00402 // virtual
00403 bool LLImageDXT::convertToDXR()
00404 {
00405         EFileFormat newformat = FORMAT_UNKNOWN;
00406         switch (mFileFormat)
00407         {
00408           case FORMAT_DXR1:
00409           case FORMAT_DXR2:
00410           case FORMAT_DXR3:
00411           case FORMAT_DXR4:
00412           case FORMAT_DXR5:
00413                 return false; // nothing to do
00414           case FORMAT_DXT1: newformat = FORMAT_DXR1; break;
00415           case FORMAT_DXT2: newformat = FORMAT_DXR2; break;
00416           case FORMAT_DXT3: newformat = FORMAT_DXR3; break;
00417           case FORMAT_DXT4: newformat = FORMAT_DXR4; break;
00418           case FORMAT_DXT5: newformat = FORMAT_DXR5; break;
00419           default:
00420                 llwarns << "convertToDXR: can not convert format: " << llformat("0x%08x",getFourCC(mFileFormat)) << llendl;
00421                 return false;
00422         }
00423         mFileFormat = newformat;
00424         S32 width = getWidth(), height = getHeight();
00425         S32 nmips = calcNumMips(width,height);
00426         S32 total_bytes = getDataSize();
00427         U8* olddata = getData();
00428         U8* newdata = new U8[total_bytes];
00429         if (!newdata)
00430         {
00431                 llerrs << "Out of memory in LLImageDXT::convertToDXR()" << llendl;
00432                 return false;
00433         }
00434         llassert(total_bytes > 0);
00435         memset(newdata, 0, total_bytes);
00436         memcpy(newdata, olddata, mHeaderSize);  /* Flawfinder: ignore */
00437         for (S32 mip=0; mip<nmips; mip++)
00438         {
00439                 S32 bytes = formatBytes(mFileFormat, width, height);
00440                 S32 newoffset = getMipOffset(mip);
00441                 S32 oldoffset = mHeaderSize + (total_bytes - newoffset - bytes);
00442                 memcpy(newdata + newoffset, olddata + oldoffset, bytes);        /* Flawfinder: ignore */
00443                 width >>= 1;
00444                 height >>= 1;
00445         }
00446         dxtfile_header_t* header = (dxtfile_header_t*)newdata;
00447         header->pixel_fmt.fourcc = getFourCC(newformat);
00448         setData(newdata, total_bytes);
00449         updateData();
00450         return true;
00451 }
00452 
00453 // virtual
00454 S32 LLImageDXT::calcHeaderSize()
00455 {
00456         return llmax(sizeof(dxtfile_header_old_t), sizeof(dxtfile_header_t));
00457 }
00458 
00459 // virtual
00460 S32 LLImageDXT::calcDataSize(S32 discard_level)
00461 {
00462         if (mFileFormat == FORMAT_UNKNOWN)
00463         {
00464                 llerrs << "calcDataSize called with unloaded LLImageDXT" << llendl;
00465                 return 0;
00466         }
00467         if (discard_level < 0)
00468         {
00469                 discard_level = mDiscardLevel;
00470         }
00471         S32 bytes = getMipOffset(discard_level); // size of header + previous mips
00472         S32 w = getWidth() >> discard_level;
00473         S32 h = getHeight() >> discard_level;
00474         bytes += formatBytes(mFileFormat,w,h);
00475         return bytes;
00476 }
00477 
00478 //============================================================================
00479 
00480 //static
00481 void LLImageDXT::extractMip(const U8 *indata, U8* mipdata, int width, int height,
00482                                                         int mip_width, int mip_height, EFileFormat format)
00483 {
00484         int initial_offset = formatBytes(format, width, height);
00485         int line_width = formatBytes(format, width, 1);
00486         int mip_line_width = formatBytes(format, mip_width, 1);
00487         int line_offset = 0;
00488 
00489         for (int ww=width>>1; ww>mip_width; ww>>=1)
00490         {
00491                 line_offset += formatBytes(format, ww, 1);
00492         }
00493 
00494         for (int h=0;h<mip_height;++h)
00495         {
00496                 int start_offset = initial_offset + line_width * h + line_offset;
00497                 memcpy(mipdata + mip_line_width*h, indata + start_offset, mip_line_width);      /* Flawfinder: ignore */
00498         }
00499 }
00500 
00501 //============================================================================

Generated on Thu Jul 1 06:08:43 2010 for Second Life Viewer by  doxygen 1.4.7