- Main Page
- Data Structures
- Files

- File List

# E:/DevIL/src-IL/src/il_dds-save.c

    00001 //-----------------------------------------------------------------------------
    00002 //
    00003 // ImageLib Sources
    00004 // Copyright (C) 2000-2009 by Denton Woods
    00005 // Last modified: 01/15/2009
    00006 //
    00007 // Filename: src-IL/src/il_dds-save.c
    00008 //
    00009 // Description: Saves a DirectDraw Surface (.dds) file.
    00010 //
    00011 //-----------------------------------------------------------------------------
    00012
    00013
    00014 #include "il_internal.h"
    00015 #include "il_dds.h"
    00016 #include "il_manip.h"
    00017 #include <limits.h>
    00018
    00019
    00020 #ifndef IL_NO_DDS
    00021
    00023 ILboolean ilSaveDds(const ILstring FileName)
    00024 {
    00025         ILHANDLE        DdsFile;
    00026         ILuint          DdsSize;
    00027
    00028         if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
    00029                 if (iFileExists(FileName)) {
    00030                         ilSetError(IL_FILE_ALREADY_EXISTS);
    00031                         return IL_FALSE;
    00032                 }
    00033         }
    00034
    00035         DdsFile = iopenw(FileName);
    00036         if (DdsFile == NULL) {
    00037                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00038                 return IL_FALSE;
    00039         }
    00040
    00041         DdsSize = ilSaveDdsF(DdsFile);
    00042         iclosew(DdsFile);
    00043
    00044         if (DdsSize == 0)
    00045                 return IL_FALSE;
    00046         return IL_TRUE;
    00047 }
    00048
    00049
    00051 ILuint ilSaveDdsF(ILHANDLE File)
    00052 {
    00053         ILuint Pos;
    00054         iSetOutputFile(File);
    00055         Pos = itellw();
    00056         if (iSaveDdsInternal() == IL_FALSE)
    00057                 return 0;  // Error occurred
    00058         return itellw() - Pos;  // Return the number of bytes written.
    00059 }
    00060
    00061
    00063 ILuint ilSaveDdsL(void *Lump, ILuint Size)
    00064 {
    00065         ILuint Pos = itellw();
    00066         iSetOutputLump(Lump, Size);
    00067         if (iSaveDdsInternal() == IL_FALSE)
    00068                 return 0;  // Error occurred
    00069         return itellw() - Pos;  // Return the number of bytes written.
    00070 }
    00071
    00072
    00074 ILuint GetCubemapInfo(ILimage* image, ILint* faces)
    00075 {
    00076         ILint   indices[] = { -1, -1, -1,  -1, -1, -1 }, i;
    00077         ILimage *img;
    00078         ILuint  ret = 0, srcMipmapCount, srcImagesCount, mipmapCount;
    00079
    00080         if (image == NULL)
    00081                 return 0;
    00082
    00083         iGetIntegervImage(image, IL_NUM_IMAGES, (ILint*) &srcImagesCount);
    00084         if (srcImagesCount != 5) //write only complete cubemaps (TODO?)
    00085                 return 0;
    00086
    00087         img = image;
    00088         iGetIntegervImage(image, IL_NUM_MIPMAPS, (ILint*) &srcMipmapCount);
    00089         mipmapCount = srcMipmapCount;
    00090
    00091         for (i = 0; i < 6; ++i) {
    00092                 switch (img->CubeFlags)
    00093                 {
    00094                         case DDS_CUBEMAP_POSITIVEX:
    00095                                 indices[i] = 0;
    00096                                 break;
    00097                         case DDS_CUBEMAP_NEGATIVEX:
    00098                                 indices[i] = 1;
    00099                                 break;
    00100                         case DDS_CUBEMAP_POSITIVEY:
    00101                                 indices[i] = 2;
    00102                                 break;
    00103                         case DDS_CUBEMAP_NEGATIVEY:
    00104                                 indices[i] = 3;
    00105                                 break;
    00106                         case DDS_CUBEMAP_POSITIVEZ:
    00107                                 indices[i] = 4;
    00108                                 break;
    00109                         case DDS_CUBEMAP_NEGATIVEZ:
    00110                                 indices[i] = 5;
    00111                                 break;
    00112                 }
    00113         iGetIntegervImage(img, IL_NUM_MIPMAPS, (ILint*) &srcMipmapCount);
    00114                 if (srcMipmapCount != mipmapCount)
    00115                         return 0; //equal # of mipmaps required
    00116
    00117                 ret |= img->CubeFlags;
    00118                 img = img->Next;
    00119         }
    00120
    00121         for (i = 0; i < 6; ++i)
    00122                 if (indices[i] == -1)
    00123                         return 0; //one face not found
    00124
    00125         if (ret != 0) //should always be true
    00126                 ret |= DDS_CUBEMAP;
    00127
    00128         for (i = 0; i < 6; ++i)
    00129                 faces[indices[i]] = i;
    00130
    00131         return ret;
    00132 }
    00133
    00134
    00135 // Internal function used to save the Dds.
    00136 ILboolean iSaveDdsInternal()
    00137 {
    00138         ILenum  DXTCFormat;
    00139         ILuint  counter, numMipMaps, image, numFaces, i;
    00140         ILubyte *CurData = NULL;
    00141         ILint   CubeTable[6] = { 0 };
    00142         ILuint  CubeFlags;
    00143
    00144         CubeFlags = GetCubemapInfo(iCurImage, CubeTable);
    00145
    00146         image = ilGetInteger(IL_CUR_IMAGE);
    00147         DXTCFormat = iGetInt(IL_DXTC_FORMAT);
    00148         WriteHeader(iCurImage, DXTCFormat, CubeFlags);
    00149
    00150         if (CubeFlags != 0)
    00151                 numFaces = ilGetInteger(IL_NUM_FACES); // Should always be 5 for now
    00152         else
    00153                 numFaces = 0;
    00154
    00155         numMipMaps = ilGetInteger(IL_NUM_MIPMAPS); //this assumes all faces have same # of mipmaps
    00156
    00157         for (i = 0; i <= numFaces; ++i) {
    00158                 for (counter = 0; counter <= numMipMaps; counter++) {
    00159                         ilBindImage(image);
    00160                         ilActiveImage(CubeTable[i]);
    00161                         ilActiveMipmap(counter);
    00162
    00163                         if (iCurImage->Origin != IL_ORIGIN_UPPER_LEFT) {
    00164                                 CurData = iCurImage->Data;
    00165                                 iCurImage->Data = iGetFlipped(iCurImage);
    00166                                 if (iCurImage->Data == NULL) {
    00167                                         iCurImage->Data = CurData;
    00168                                         return IL_FALSE;
    00169                                 }
    00170                         }
    00171
    00172                         if (!Compress(iCurImage, DXTCFormat))
    00173                                 return IL_FALSE;
    00174
    00175                         if (iCurImage->Origin != IL_ORIGIN_UPPER_LEFT) {
    00176                                 ifree(iCurImage->Data);
    00177                                 iCurImage->Data = CurData;
    00178                         }
    00179                 }
    00180
    00181         }
    00182
    00183         return IL_TRUE;
    00184 }
    00185
    00186
    00187 // @TODO:  Finish this, as it is incomplete.
    00188 ILboolean WriteHeader(ILimage *Image, ILenum DXTCFormat, ILuint CubeFlags)
    00189 {
    00190         ILuint i, FourCC, Flags1 = 0, Flags2 = 0, ddsCaps1 = 0,
    00191         LinearSize, BlockSize, ddsCaps2 = 0;
    00192
    00193         Flags1 |= DDS_LINEARSIZE | DDS_MIPMAPCOUNT
    00194                         | DDS_WIDTH | DDS_HEIGHT | DDS_CAPS | DDS_PIXELFORMAT;
    00195         Flags2 |= DDS_FOURCC;
    00196
    00197         if (Image->Depth > 1)
    00198                 Flags1 |= DDS_DEPTH;
    00199
    00200         // @TODO:  Fix the pre-multiplied alpha problem.
    00201         if (DXTCFormat == IL_DXT2)
    00202                 DXTCFormat = IL_DXT3;
    00203         else if (DXTCFormat == IL_DXT4)
    00204                 DXTCFormat = IL_DXT5;
    00205
    00206         switch (DXTCFormat)
    00207         {
    00208                 case IL_DXT1:
    00209                 case IL_DXT1A:
    00210                         FourCC = IL_MAKEFOURCC('D','X','T','1');
    00211                         break;
    00212                 case IL_DXT2:
    00213                         FourCC = IL_MAKEFOURCC('D','X','T','2');
    00214                         break;
    00215                 case IL_DXT3:
    00216                         FourCC = IL_MAKEFOURCC('D','X','T','3');
    00217                         break;
    00218                 case IL_DXT4:
    00219                         FourCC = IL_MAKEFOURCC('D','X','T','4');
    00220                         break;
    00221                 case IL_DXT5:
    00222                         FourCC = IL_MAKEFOURCC('D','X','T','5');
    00223                         break;
    00224                 case IL_ATI1N:
    00225                         FourCC = IL_MAKEFOURCC('A', 'T', 'I', '1');
    00226                         break;
    00227                 case IL_3DC:
    00228                         FourCC = IL_MAKEFOURCC('A','T','I','2');
    00229                         break;
    00230                 case IL_RXGB:
    00231                         FourCC = IL_MAKEFOURCC('R','X','G','B');
    00232                         break;
    00233                 default:
    00234                         // Error!
    00235                         ilSetError(IL_INTERNAL_ERROR);  // Should never happen, though.
    00236                         return IL_FALSE;
    00237         }
    00238
    00239         iwrite("DDS ", 1, 4);
    00240         SaveLittleUInt(124);            // Size1
    00241         SaveLittleUInt(Flags1);         // Flags1
    00242         SaveLittleUInt(Image->Height);
    00243         SaveLittleUInt(Image->Width);
    00244
    00245         if (DXTCFormat == IL_DXT1 || DXTCFormat == IL_DXT1A || DXTCFormat == IL_ATI1N) {
    00246                 BlockSize = 8;
    00247         }
    00248         else {
    00249                 BlockSize = 16;
    00250         }
    00251         LinearSize = (((Image->Width + 3)/4) * ((Image->Height + 3)/4)) * BlockSize * Image->Depth;
    00252
    00253         /*
    00254         // doing this is actually wrong, linear size is only size of one cube face
    00255         if (CubeFlags != 0) {
    00256                 ILint numFaces = 0;
    00257                 for (i = 0; i < 6; ++i)
    00258                         if (CubeFlags & CubemapDirections[i])
    00259                                 ++numFaces;
    00260
    00261                 LinearSize *= numFaces;
    00262         }
    00263         */
    00264
    00265         SaveLittleUInt(LinearSize);     // LinearSize (TODO: change this when uncompressed formats are supported)
    00266
    00267         if (Image->Depth > 1) {
    00268                 SaveLittleUInt(Image->Depth);                   // Depth
    00269                 ddsCaps2 |= DDS_VOLUME;
    00270         }
    00271         else
    00272                 SaveLittleUInt(0);                                              // Depth
    00273
    00274         SaveLittleUInt(ilGetInteger(IL_NUM_MIPMAPS) + 1);  // MipMapCount
    00275         SaveLittleUInt(0);                      // AlphaBitDepth
    00276
    00277         for (i = 0; i < 10; i++)
    00278                 SaveLittleUInt(0);              // Not used
    00279
    00280         SaveLittleUInt(32);                     // Size2
    00281         SaveLittleUInt(Flags2);         // Flags2
    00282         SaveLittleUInt(FourCC);         // FourCC
    00283         SaveLittleUInt(0);                      // RGBBitCount
    00284         SaveLittleUInt(0);                      // RBitMask
    00285         SaveLittleUInt(0);                      // GBitMask
    00286         SaveLittleUInt(0);                      // BBitMask
    00287         SaveLittleUInt(0);                      // RGBAlphaBitMask
    00288         ddsCaps1 |= DDS_TEXTURE;
    00289         //changed 20040516: set mipmap flag on mipmap images
    00290         //(non-compressed .dds files still not supported,
    00291         //though)
    00292         if (ilGetInteger(IL_NUM_MIPMAPS) > 0)
    00293                 ddsCaps1 |= DDS_MIPMAP | DDS_COMPLEX;
    00294         if (CubeFlags != 0) {
    00295                 ddsCaps1 |= DDS_COMPLEX;
    00296                 ddsCaps2 |= CubeFlags;
    00297         }
    00298
    00299         SaveLittleUInt(ddsCaps1);       // ddsCaps1
    00300
    00301         SaveLittleUInt(ddsCaps2);       // ddsCaps2
    00302         SaveLittleUInt(0);                      // ddsCaps3
    00303         SaveLittleUInt(0);                      // ddsCaps4
    00304         SaveLittleUInt(0);                      // TextureStage
    00305
    00306         return IL_TRUE;
    00307 }
    00308
    00309 #endif//IL_NO_DDS
    00310
    00311
    00312 ILuint ILAPIENTRY ilGetDXTCData(void *Buffer, ILuint BufferSize, ILenum DXTCFormat)
    00313 {
    00314         ILubyte *CurData = NULL;
    00315         ILuint  retVal;
    00316
    00317         ILint BlockNum;
    00318
    00319         if (Buffer == NULL) {  // Return the number that will be written with a subsequent call.
    00320                 BlockNum = ((iCurImage->Width + 3)/4) * ((iCurImage->Height + 3)/4)
    00321                                         * iCurImage->Depth;
    00322
    00323                 switch (DXTCFormat)
    00324                 {
    00325                         case IL_DXT1:
    00326                         case IL_DXT1A:
    00327                         case IL_ATI1N:
    00328                                 return BlockNum * 8;
    00329                         case IL_DXT3:
    00330                         case IL_DXT5:
    00331                         case IL_3DC:
    00332                         case IL_RXGB:
    00333                                 return BlockNum * 16;
    00334                         default:
    00335                                 ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00336                                 return 0;
    00337                 }
    00338         }
    00339
    00340         if (DXTCFormat == iCurImage->DxtcFormat && iCurImage->DxtcSize && iCurImage->DxtcData) {
    00341                 memcpy(Buffer, iCurImage->DxtcData, IL_MIN(BufferSize, iCurImage->DxtcSize));
    00342                 return IL_MIN(BufferSize, iCurImage->DxtcSize);
    00343         }
    00344
    00345         if (iCurImage->Origin != IL_ORIGIN_UPPER_LEFT) {
    00346                 CurData = iCurImage->Data;
    00347                 iCurImage->Data = iGetFlipped(iCurImage);
    00348                 if (iCurImage->Data == NULL) {
    00349                         iCurImage->Data = CurData;
    00350                         return 0;
    00351                 }
    00352         }
    00353
    00354         //@TODO: Is this the best way to do this?
    00355         iSetOutputLump(Buffer, BufferSize);
    00356         retVal = Compress(iCurImage, DXTCFormat);
    00357
    00358         if (iCurImage->Origin != IL_ORIGIN_UPPER_LEFT) {
    00359                 ifree(iCurImage->Data);
    00360                 iCurImage->Data = CurData;
    00361         }
    00362
    00363         return retVal;
    00364 }
    00365
    00366
    00367 // Added the next two functions based on Charles Bloom's rant at
    00368 //  http://cbloomrants.blogspot.com/2008/12/12-08-08-dxtc-summary.html.
    00369 //  This code is by ryg and from the Molly Rocket forums:
    00370 //  https://mollyrocket.com/forums/viewtopic.php?t=392.
    00371 static ILint Mul8Bit(ILint a, ILint b)
    00372 {
    00373         ILint t = a*b + 128;
    00374         return (t + (t >> 8)) >> 8;
    00375 }
    00376
    00377 ILushort As16Bit(ILint r, ILint g, ILint b)
    00378 {
    00379         return (Mul8Bit(r,31) << 11) + (Mul8Bit(g,63) << 5) + Mul8Bit(b,31);
    00380 }
    00381
    00382
    00383 ILushort *CompressTo565(ILimage *Image)
    00384 {
    00385         ILimage         *TempImage;
    00386         ILushort        *Data;
    00387         ILuint          i, j;
    00388
    00389         if ((Image->Type != IL_UNSIGNED_BYTE && Image->Type != IL_BYTE) || Image->Format == IL_COLOUR_INDEX) {
    00390                 TempImage = iConvertImage(iCurImage, IL_BGRA, IL_UNSIGNED_BYTE);  // @TODO: Needs to be BGRA.
    00391                 if (TempImage == NULL)
    00392                         return NULL;
    00393         }
    00394         else {
    00395                 TempImage = Image;
    00396         }
    00397
    00398         Data = (ILushort*)ialloc(iCurImage->Width * iCurImage->Height * 2 * iCurImage->Depth);
    00399         if (Data == NULL) {
    00400                 if (TempImage != Image)
    00401                         ilCloseImage(TempImage);
    00402                 return NULL;
    00403         }
    00404
    00405         //changed 20040623: Use TempImages format :)
    00406         switch (TempImage->Format)
    00407         {
    00408                 case IL_RGB:
    00409                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 3, j++) {
    00410                                 /*Data[j]  = (TempImage->Data[i  ] >> 3) << 11;
    00411                                 Data[j] |= (TempImage->Data[i+1] >> 2) << 5;
    00412                                 Data[j] |=  TempImage->Data[i+2] >> 3;*/
    00413                                 Data[j] = As16Bit(TempImage->Data[i], TempImage->Data[i+1], TempImage->Data[i+2]);
    00414                         }
    00415                         break;
    00416
    00417                 case IL_RGBA:
    00418                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 4, j++) {
    00419                                 /*Data[j]  = (TempImage->Data[i  ] >> 3) << 11;
    00420                                 Data[j] |= (TempImage->Data[i+1] >> 2) << 5;
    00421                                 Data[j] |=  TempImage->Data[i+2] >> 3;*/
    00422                                 Data[j] = As16Bit(TempImage->Data[i], TempImage->Data[i+1], TempImage->Data[i+2]);
    00423                         }
    00424                         break;
    00425
    00426                 case IL_BGR:
    00427                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 3, j++) {
    00428                                 /*Data[j]  = (TempImage->Data[i+2] >> 3) << 11;
    00429                                 Data[j] |= (TempImage->Data[i+1] >> 2) << 5;
    00430                                 Data[j] |=  TempImage->Data[i  ] >> 3;*/
    00431                                 Data[j] = As16Bit(TempImage->Data[i+2], TempImage->Data[i+1], TempImage->Data[i]);
    00432                         }
    00433                         break;
    00434
    00435                 case IL_BGRA:
    00436                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 4, j++) {
    00437                                 /*Data[j]  = (TempImage->Data[i+2] >> 3) << 11;
    00438                                 Data[j] |= (TempImage->Data[i+1] >> 2) << 5;
    00439                                 Data[j] |=  TempImage->Data[i  ] >> 3;*/
    00440                                 Data[j] = As16Bit(TempImage->Data[i+2], TempImage->Data[i+1], TempImage->Data[i]);
    00441                         }
    00442                         break;
    00443
    00444                 case IL_LUMINANCE:
    00445                         for (i = 0, j = 0; i < TempImage->SizeOfData; i++, j++) {
    00446                                 //@TODO: Do better conversion here.
    00447                                 /*Data[j]  = (TempImage->Data[i] >> 3) << 11;
    00448                                 Data[j] |= (TempImage->Data[i] >> 2) << 5;
    00449                                 Data[j] |=  TempImage->Data[i] >> 3;*/
    00450                                 Data[j] = As16Bit(TempImage->Data[i], TempImage->Data[i], TempImage->Data[i]);
    00451                         }
    00452                         break;
    00453
    00454                 case IL_LUMINANCE_ALPHA:
    00455                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 2, j++) {
    00456                                 //@TODO: Do better conversion here.
    00457                                 /*Data[j]  = (TempImage->Data[i] >> 3) << 11;
    00458                                 Data[j] |= (TempImage->Data[i] >> 2) << 5;
    00459                                 Data[j] |=  TempImage->Data[i] >> 3;*/
    00460                                 Data[j] = As16Bit(TempImage->Data[i], TempImage->Data[i], TempImage->Data[i]);
    00461                         }
    00462                         break;
    00463
    00464                 case IL_ALPHA:
    00465                         memset(Data, 0, iCurImage->Width * iCurImage->Height * 2 * iCurImage->Depth);
    00466                         break;
    00467         }
    00468
    00469         if (TempImage != Image)
    00470                 ilCloseImage(TempImage);
    00471
    00472         return Data;
    00473 }
    00474
    00475
    00476 ILubyte *CompressTo88(ILimage *Image)
    00477 {
    00478         ILimage         *TempImage;
    00479         ILubyte         *Data;
    00480         ILuint          i, j;
    00481
    00482         if ((Image->Type != IL_UNSIGNED_BYTE && Image->Type != IL_BYTE) || Image->Format == IL_COLOUR_INDEX) {
    00483                 TempImage = iConvertImage(iCurImage, IL_BGR, IL_UNSIGNED_BYTE);  // @TODO: Needs to be BGRA.
    00484                 if (TempImage == NULL)
    00485                         return NULL;
    00486         }
    00487         else {
    00488                 TempImage = Image;
    00489         }
    00490
    00491         Data = (ILubyte*)ialloc(iCurImage->Width * iCurImage->Height * 2 * iCurImage->Depth);
    00492         if (Data == NULL) {
    00493                 if (TempImage != Image)
    00494                         ilCloseImage(TempImage);
    00495                 return NULL;
    00496         }
    00497
    00498         //changed 20040623: Use TempImage's format :)
    00499         switch (TempImage->Format)
    00500         {
    00501                 case IL_RGB:
    00502                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 3, j += 2) {
    00503                                 Data[j  ] = TempImage->Data[i+1];
    00504                                 Data[j+1] = TempImage->Data[i  ];
    00505                         }
    00506                         break;
    00507
    00508                 case IL_RGBA:
    00509                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 4, j += 2) {
    00510                                 Data[j  ] = TempImage->Data[i+1];
    00511                                 Data[j+1] = TempImage->Data[i  ];
    00512                         }
    00513                         break;
    00514
    00515                 case IL_BGR:
    00516                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 3, j += 2) {
    00517                                 Data[j  ] = TempImage->Data[i+1];
    00518                                 Data[j+1] = TempImage->Data[i+2];
    00519                         }
    00520                         break;
    00521
    00522                 case IL_BGRA:
    00523                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 4, j += 2) {
    00524                                 Data[j  ] = TempImage->Data[i+1];
    00525                                 Data[j+1] = TempImage->Data[i+2];
    00526                         }
    00527                         break;
    00528
    00529                 case IL_LUMINANCE:
    00530                 case IL_LUMINANCE_ALPHA:
    00531                         for (i = 0, j = 0; i < TempImage->SizeOfData; i++, j += 2) {
    00532                                 Data[j  ] = Data[j+1] = 0; //??? Luminance is no normal map format...
    00533                         }
    00534                         break;
    00535         }
    00536
    00537         if (TempImage != Image)
    00538                 ilCloseImage(TempImage);
    00539
    00540         return Data;
    00541 }
    00542
    00543 void CompressToRXGB(ILimage *Image, ILushort** xgb, ILubyte** r)
    00544 {
    00545         ILimage         *TempImage;
    00546         ILuint          i, j;
    00547         ILushort        *Data;
    00548         ILubyte         *Alpha;
    00549
    00550         *xgb = NULL;
    00551         *r = NULL;
    00552
    00553         if ((Image->Type != IL_UNSIGNED_BYTE && Image->Type != IL_BYTE) || Image->Format == IL_COLOUR_INDEX) {
    00554                 TempImage = iConvertImage(iCurImage, IL_BGR, IL_UNSIGNED_BYTE);  // @TODO: Needs to be BGRA.
    00555                 if (TempImage == NULL)
    00556                         return;
    00557         }
    00558         else {
    00559                 TempImage = Image;
    00560         }
    00561
    00562         *xgb = (ILushort*)ialloc(iCurImage->Width * iCurImage->Height * 2 * iCurImage->Depth);
    00563         *r = (ILubyte*)ialloc(iCurImage->Width * iCurImage->Height * iCurImage->Depth);
    00564         if (*xgb == NULL || *r == NULL) {
    00565                 if (TempImage != Image)
    00566                         ilCloseImage(TempImage);
    00567                 return;
    00568         }
    00569
    00570         //Alias pointers to be able to use copy'n'pasted code :)
    00571         Data = *xgb;
    00572         Alpha = *r;
    00573
    00574         switch (TempImage->Format)
    00575         {
    00576                 case IL_RGB:
    00577                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 3, j++) {
    00578                                 Alpha[j] = TempImage->Data[i];
    00579                                 Data[j] = (TempImage->Data[i+1] >> 2) << 5;
    00580                                 Data[j] |=  TempImage->Data[i+2] >> 3;
    00581                         }
    00582                         break;
    00583
    00584                 case IL_RGBA:
    00585                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 4, j++) {
    00586                                 Alpha[j]  = TempImage->Data[i];
    00587                                 Data[j] = (TempImage->Data[i+1] >> 2) << 5;
    00588                                 Data[j] |=  TempImage->Data[i+2] >> 3;
    00589                         }
    00590                         break;
    00591
    00592                 case IL_BGR:
    00593                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 3, j++) {
    00594                                 Alpha[j]  = TempImage->Data[i+2];
    00595                                 Data[j] = (TempImage->Data[i+1] >> 2) << 5;
    00596                                 Data[j] |=  TempImage->Data[i  ] >> 3;
    00597                         }
    00598                         break;
    00599
    00600                 case IL_BGRA:
    00601                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 4, j++) {
    00602                                 Alpha[j]  = TempImage->Data[i+2];
    00603                                 Data[j] = (TempImage->Data[i+1] >> 2) << 5;
    00604                                 Data[j] |=  TempImage->Data[i  ] >> 3;
    00605                         }
    00606                         break;
    00607
    00608                 case IL_LUMINANCE:
    00609                         for (i = 0, j = 0; i < TempImage->SizeOfData; i++, j++) {
    00610                                 Alpha[j]  = TempImage->Data[i];
    00611                                 Data[j] = (TempImage->Data[i] >> 2) << 5;
    00612                                 Data[j] |=  TempImage->Data[i] >> 3;
    00613                         }
    00614                         break;
    00615
    00616                 case IL_LUMINANCE_ALPHA:
    00617                         for (i = 0, j = 0; i < TempImage->SizeOfData; i += 2, j++) {
    00618                                 Alpha[j]  = TempImage->Data[i];
    00619                                 Data[j] = (TempImage->Data[i] >> 2) << 5;
    00620                                 Data[j] |=  TempImage->Data[i] >> 3;
    00621                         }
    00622                         break;
    00623         }
    00624
    00625         if (TempImage != Image)
    00626                 ilCloseImage(TempImage);
    00627 }
    00628
    00629
    00630 ILuint Compress(ILimage *Image, ILenum DXTCFormat)
    00631 {
    00632         ILushort        *Data, Block[16], ex0, ex1, *Runner16, t0, t1;
    00633         ILuint          x, y, z, i, BitMask, DXTCSize;//, Rms1, Rms2;
    00634         ILubyte         *Alpha, AlphaBlock[16], AlphaBitMask[6], /*AlphaOut[16],*/ a0, a1;
    00635         ILboolean       HasAlpha;
    00636         ILuint          Count = 0;
    00637         ILubyte         *Data3Dc, *Runner8, *ByteData, *BlockData;
    00638
    00639         if (DXTCFormat == IL_3DC) {
    00640                 Data3Dc = CompressTo88(Image);
    00641                 if (Data3Dc == NULL)
    00642                         return 0;
    00643
    00644                 Runner8 = Data3Dc;
    00645
    00646                 for (z = 0; z < Image->Depth; z++) {
    00647                         for (y = 0; y < Image->Height; y += 4) {
    00648                                 for (x = 0; x < Image->Width; x += 4) {
    00649                                         Get3DcBlock(AlphaBlock, Runner8, Image, x, y, 0);
    00650                                         ChooseAlphaEndpoints(AlphaBlock, &a0, &a1);
    00651                                         GenAlphaBitMask(a0, a1, AlphaBlock, AlphaBitMask, NULL);
    00652                                         iputc(a0);
    00653                                         iputc(a1);
    00654                                         iwrite(AlphaBitMask, 1, 6);
    00655
    00656                                         Get3DcBlock(AlphaBlock, Runner8, Image, x, y, 1);
    00657                                         ChooseAlphaEndpoints(AlphaBlock, &a0, &a1);
    00658                                         GenAlphaBitMask(a0, a1, AlphaBlock, AlphaBitMask, NULL);
    00659                                         iputc(a0);
    00660                                         iputc(a1);
    00661                                         iwrite(AlphaBitMask, 1, 6);
    00662
    00663                                         Count += 16;
    00664                                 }
    00665                         }
    00666                         Runner8 += Image->Width * Image->Height * 2;
    00667                 }
    00668                 ifree(Data3Dc);
    00669         }
    00670
    00671         else if (DXTCFormat == IL_ATI1N)
    00672         {
    00673                 ILimage *TempImage;
    00674
    00675                 if (Image->Bpp != 1) {
    00676                         TempImage = iConvertImage(iCurImage, IL_LUMINANCE, IL_UNSIGNED_BYTE);
    00677                         if (TempImage == NULL)
    00678                                 return 0;
    00679                 }
    00680                 else {
    00681                         TempImage = Image;
    00682                 }
    00683
    00684                 Runner8 = TempImage->Data;
    00685
    00686                 for (z = 0; z < Image->Depth; z++) {
    00687                         for (y = 0; y < Image->Height; y += 4) {
    00688                                 for (x = 0; x < Image->Width; x += 4) {
    00689                                         GetAlphaBlock(AlphaBlock, Runner8, Image, x, y);
    00690                                         ChooseAlphaEndpoints(AlphaBlock, &a0, &a1);
    00691                                         GenAlphaBitMask(a0, a1, AlphaBlock, AlphaBitMask, NULL);
    00692                                         iputc(a0);
    00693                                         iputc(a1);
    00694                                         iwrite(AlphaBitMask, 1, 6);
    00695                                         Count += 8;
    00696                                 }
    00697                         }
    00698                         Runner8 += Image->Width * Image->Height;
    00699                 }
    00700
    00701                 if (TempImage != Image)
    00702                         ilCloseImage(TempImage);
    00703         }
    00704         else
    00705         {
    00706                 // We want to try nVidia compression first, because it is the fastest.
    00707 #ifdef IL_USE_DXTC_NVIDIA
    00708                 if (ilIsEnabled(IL_NVIDIA_COMPRESS) && Image->Depth == 1) {  // See if we need to use the nVidia Texture Tools library.
    00709                         if (DXTCFormat == IL_DXT1 || DXTCFormat == IL_DXT1A || DXTCFormat == IL_DXT3 || DXTCFormat == IL_DXT5) {
    00710                                 // NVTT needs data as BGRA 32-bit.
    00711                                 if (Image->Format != IL_BGRA || Image->Type != IL_UNSIGNED_BYTE) {  // No need to convert if already this format/type.
    00712                                         ByteData = ilConvertBuffer(Image->SizeOfData, Image->Format, IL_BGRA, Image->Type, IL_UNSIGNED_BYTE, Image->Data);
    00713                                         if (ByteData == NULL)
    00714                                                 return 0;
    00715                                 }
    00716                                 else
    00717                                         ByteData = Image->Data;
    00718
    00719                                 // Here's where all the compression and writing goes on.
    00720                                 if (!ilNVidiaCompressDXTFile(ByteData, Image->Width, Image->Height, 1, DXTCFormat))
    00721                                         return 0;
    00722
    00723                                 if (ByteData != Image->Data)
    00724                                         ifree(ByteData);
    00725
    00726                                 return Image->Width * Image->Height * 4;  // Either compresses all or none.
    00727                         }
    00728                 }
    00729 #endif//IL_USE_DXTC_NVIDIA
    00730
    00731                 // libsquish generates better quality output than DevIL does, so we try it next.
    00732 #ifdef IL_USE_DXTC_SQUISH
    00733                 if (ilIsEnabled(IL_SQUISH_COMPRESS) && Image->Depth == 1) {  // See if we need to use the nVidia Texture Tools library.
    00734                         if (DXTCFormat == IL_DXT1 || DXTCFormat == IL_DXT1A || DXTCFormat == IL_DXT3 || DXTCFormat == IL_DXT5) {
    00735                                 // libsquish needs data as RGBA 32-bit.
    00736                                 if (Image->Format != IL_RGBA || Image->Type != IL_UNSIGNED_BYTE) {  // No need to convert if already this format/type.
    00737                                         ByteData = ilConvertBuffer(Image->SizeOfData, Image->Format, IL_RGBA, Image->Type, IL_UNSIGNED_BYTE, Image->Data);
    00738                                         if (ByteData == NULL)
    00739                                                 return 0;
    00740                                 }
    00741                                 else
    00742                                         ByteData = Image->Data;
    00743
    00744                                 // Get compressed data here.
    00745                                 BlockData = ilSquishCompressDXT(ByteData, Image->Width, Image->Height, 1, DXTCFormat, &DXTCSize);
    00746                                 if (BlockData == NULL)
    00747                                         return 0;
    00748
    00749                                 if (iwrite(BlockData, 1, DXTCSize) != DXTCSize) {
    00750                                         if (ByteData != Image->Data)
    00751                                                 ifree(ByteData);
    00752                                         ifree(BlockData);
    00753                                         return 0;
    00754                                 }
    00755
    00756                                 if (ByteData != Image->Data)
    00757                                         ifree(ByteData);
    00758                                 ifree(BlockData);
    00759
    00760                                 return Image->Width * Image->Height * 4;  // Either compresses all or none.
    00761                         }
    00762                 }
    00763 #endif//IL_USE_DXTC_SQUISH
    00764
    00765                 if (DXTCFormat != IL_RXGB) {
    00766                         Data = CompressTo565(Image);
    00767                         if (Data == NULL)
    00768                                 return 0;
    00769
    00770                         Alpha = ilGetAlpha(IL_UNSIGNED_BYTE);
    00771                         if (Alpha == NULL) {
    00772                                 ifree(Data);
    00773                                 return 0;
    00774                         }
    00775                 }
    00776                 else {
    00777                         CompressToRXGB(Image, &Data, &Alpha);
    00778                         if (Data == NULL || Alpha == NULL) {
    00779                                 if (Data != NULL)
    00780                                         ifree(Data);
    00781                                 if (Alpha != NULL)
    00782                                         ifree(Alpha);
    00783                                 return 0;
    00784                         }
    00785                 }
    00786
    00787                 Runner8 = Alpha;
    00788                 Runner16 = Data;
    00789
    00790                 switch (DXTCFormat)
    00791                 {
    00792                         case IL_DXT1:
    00793                         case IL_DXT1A:
    00794                                 for (z = 0; z < Image->Depth; z++) {
    00795                                         for (y = 0; y < Image->Height; y += 4) {
    00796                                                 for (x = 0; x < Image->Width; x += 4) {
    00797                                                         GetAlphaBlock(AlphaBlock, Runner8, Image, x, y);
    00798                                                         HasAlpha = IL_FALSE;
    00799                                                         for (i = 0 ; i < 16; i++) {
    00800                                                                 if (AlphaBlock[i] < 128) {
    00801                                                                         HasAlpha = IL_TRUE;
    00802                                                                         break;
    00803                                                                 }
    00804                                                         }
    00805
    00806                                                         GetBlock(Block, Runner16, Image, x, y);
    00807                                                         ChooseEndpoints(Block, &ex0, &ex1);
    00808                                                         CorrectEndDXT1(&ex0, &ex1, HasAlpha);
    00809                                                         SaveLittleUShort(ex0);
    00810                                                         SaveLittleUShort(ex1);
    00811                                                         if (HasAlpha)
    00812                                                                 BitMask = GenBitMask(ex0, ex1, 3, Block, AlphaBlock, NULL);
    00813                                                         else
    00814                                                                 BitMask = GenBitMask(ex0, ex1, 4, Block, NULL, NULL);
    00815                                                         SaveLittleUInt(BitMask);
    00816                                                         Count += 8;
    00817                                                 }
    00818                                         }
    00819
    00820                                         Runner16 += Image->Width * Image->Height;
    00821                                         Runner8 += Image->Width * Image->Height;
    00822                                 }
    00823                                 break;
    00824
    00825                         /*case IL_DXT2:
    00826                                 for (y = 0; y < Image->Height; y += 4) {
    00827                                         for (x = 0; x < Image->Width; x += 4) {
    00828                                                 GetAlphaBlock(AlphaBlock, Alpha, Image, x, y);
    00829                                                 for (i = 0; i < 16; i += 2) {
    00830                                                         iputc((ILubyte)(((AlphaBlock[i] >> 4) << 4) | (AlphaBlock[i+1] >> 4)));
    00831                                                 }
    00832
    00833                                                 GetBlock(Block, Data, Image, x, y);
    00834                                                 PreMult(Block, AlphaBlock);
    00835                                                 ChooseEndpoints(Block, &ex0, &ex1);
    00836                                                 SaveLittleUShort(ex0);
    00837                                                 SaveLittleUShort(ex1);
    00838                                                 BitMask = GenBitMask(ex0, ex1, 4, Block, NULL, NULL);
    00839                                                 SaveLittleUInt(BitMask);
    00840                                         }
    00841                                 }
    00842                                 break;*/
    00843
    00844                         case IL_DXT3:
    00845                                 for (z = 0; z < Image->Depth; z++) {
    00846                                         for (y = 0; y < Image->Height; y += 4) {
    00847                                                 for (x = 0; x < Image->Width; x += 4) {
    00848                                                         GetAlphaBlock(AlphaBlock, Runner8, Image, x, y);
    00849                                                         for (i = 0; i < 16; i += 2) {
    00850                                                                 iputc((ILubyte)(((AlphaBlock[i+1] >> 4) << 4) | (AlphaBlock[i] >> 4)));
    00851                                                         }
    00852
    00853                                                         GetBlock(Block, Runner16, Image, x, y);
    00854                                                         ChooseEndpoints(Block, &t0, &t1);
    00855                                                         ex0 = IL_MAX(t0, t1);
    00856                                                         ex1 = IL_MIN(t0, t1);
    00857                                                         CorrectEndDXT1(&ex0, &ex1, 0);
    00858                                                         SaveLittleUShort(ex0);
    00859                                                         SaveLittleUShort(ex1);
    00860                                                         BitMask = GenBitMask(ex0, ex1, 4, Block, NULL, NULL);
    00861                                                         SaveLittleUInt(BitMask);
    00862                                                         Count += 16;
    00863                                                 }
    00864                                         }
    00865
    00866                                         Runner16 += Image->Width * Image->Height;
    00867                                         Runner8 += Image->Width * Image->Height;
    00868                                 }
    00869                                 break;
    00870
    00871                         case IL_RXGB:
    00872                         case IL_DXT5:
    00873                                 for (z = 0; z < Image->Depth; z++) {
    00874                                         for (y = 0; y < Image->Height; y += 4) {
    00875                                                 for (x = 0; x < Image->Width; x += 4) {
    00876                                                         GetAlphaBlock(AlphaBlock, Runner8, Image, x, y);
    00877                                                         ChooseAlphaEndpoints(AlphaBlock, &a0, &a1);
    00878                                                         GenAlphaBitMask(a0, a1, AlphaBlock, AlphaBitMask, NULL/*AlphaOut*/);
    00879                                                         /*Rms2 = RMSAlpha(AlphaBlock, AlphaOut);
    00880                                                         GenAlphaBitMask(a0, a1, 8, AlphaBlock, AlphaBitMask, AlphaOut);
    00881                                                         Rms1 = RMSAlpha(AlphaBlock, AlphaOut);
    00882                                                         if (Rms2 <= Rms1) {  // Yeah, we have to regenerate...
    00883                                                                 GenAlphaBitMask(a0, a1, 6, AlphaBlock, AlphaBitMask, AlphaOut);
    00884                                                                 Rms2 = a1;  // Just reuse Rms2 as a temporary variable...
    00885                                                                 a1 = a0;
    00886                                                                 a0 = Rms2;
    00887                                                         }*/
    00888                                                         iputc(a0);
    00889                                                         iputc(a1);
    00890                                                         iwrite(AlphaBitMask, 1, 6);
    00891
    00892                                                         GetBlock(Block, Runner16, Image, x, y);
    00893                                                         ChooseEndpoints(Block, &t0, &t1);
    00894                                                         ex0 = IL_MAX(t0, t1);
    00895                                                         ex1 = IL_MIN(t0, t1);
    00896                                                         CorrectEndDXT1(&ex0, &ex1, 0);
    00897                                                         SaveLittleUShort(ex0);
    00898                                                         SaveLittleUShort(ex1);
    00899                                                         BitMask = GenBitMask(ex0, ex1, 4, Block, NULL, NULL);
    00900                                                         SaveLittleUInt(BitMask);
    00901                                                         Count += 16;
    00902                                                 }
    00903                                         }
    00904
    00905                                         Runner16 += Image->Width * Image->Height;
    00906                                         Runner8 += Image->Width * Image->Height;
    00907                                 }
    00908                                 break;
    00909                 }
    00910
    00911                 ifree(Data);
    00912                 ifree(Alpha);
    00913         } //else no 3dc
    00914
    00915         return Count;  // Returns 0 if no compression was done.
    00916 }
    00917
    00918
    00919 // Assumed to be 16-bit (5:6:5).
    00920 ILboolean GetBlock(ILushort *Block, ILushort *Data, ILimage *Image, ILuint XPos, ILuint YPos)
    00921 {
    00922     ILuint x, y, i = 0, Offset = YPos * Image->Width + XPos;
    00923
    00924         for (y = 0; y < 4; y++) {
    00925                 for (x = 0; x < 4; x++) {
    00926                     if (XPos + x < Image->Width && YPos + y < Image->Height)
    00927                                 Block[i++] = Data[Offset + x];
    00928                         else
    00929                                 // Variant of bugfix from https://sourceforge.net/forum/message.php?msg_id=5486779.
    00930                                 //  If we are out of bounds of the image, just copy the adjacent data.
    00931                             Block[i++] = Data[Offset];
    00932                 }
    00933                 // We do not want to read past the end of the image.
    00934                 if (YPos + y + 1 < Image->Height)
    00935                         Offset += Image->Width;
    00936         }
    00937
    00938         return IL_TRUE;
    00939 }
    00940
    00941
    00942 ILboolean GetAlphaBlock(ILubyte *Block, ILubyte *Data, ILimage *Image, ILuint XPos, ILuint YPos)
    00943 {
    00944         ILuint x, y, i = 0, Offset = YPos * Image->Width + XPos;
    00945
    00946         for (y = 0; y < 4; y++) {
    00947                 for (x = 0; x < 4; x++) {
    00948                     if (XPos + x < Image->Width && YPos + y < Image->Height)
    00949                                 Block[i++] = Data[Offset + x];
    00950                         else
    00951                                 // Variant of bugfix from https://sourceforge.net/forum/message.php?msg_id=5486779.
    00952                                 //  If we are out of bounds of the image, just copy the adjacent data.
    00953                             Block[i++] = Data[Offset];
    00954                 }
    00955                 // We do not want to read past the end of the image.
    00956                 if (YPos + y + 1 < Image->Height)
    00957                         Offset += Image->Width;
    00958         }
    00959
    00960         return IL_TRUE;
    00961 }
    00962
    00963 ILboolean Get3DcBlock(ILubyte *Block, ILubyte *Data, ILimage *Image, ILuint XPos, ILuint YPos, int channel)
    00964 {
    00965         ILuint x, y, i = 0, Offset = 2*(YPos * Image->Width + XPos) + channel;
    00966
    00967         for (y = 0; y < 4; y++) {
    00968                 for (x = 0; x < 4; x++) {
    00969                         if (x < Image->Width && y < Image->Height)
    00970                 Block[i++] = Data[Offset + 2*x];
    00971             else
    00972                 Block[i++] = Data[Offset];
    00973                 }
    00974         Offset += 2*Image->Width;
    00975         }
    00976
    00977         return IL_TRUE;
    00978 }
    00979
    00980
    00981 void ShortToColor565(ILushort Pixel, Color565 *Colour)
    00982 {
    00983         Colour->nRed   = (Pixel & 0xF800) >> 11;
    00984         Colour->nGreen = (Pixel & 0x07E0) >> 5;
    00985         Colour->nBlue  = (Pixel & 0x001F);
    00986         return;
    00987 }
    00988
    00989
    00990 void ShortToColor888(ILushort Pixel, Color888 *Colour)
    00991 {
    00992         Colour->r = ((Pixel & 0xF800) >> 11) << 3;
    00993         Colour->g = ((Pixel & 0x07E0) >> 5)  << 2;
    00994         Colour->b = ((Pixel & 0x001F))       << 3;
    00995         return;
    00996 }
    00997
    00998
    00999 ILushort Color565ToShort(Color565 *Colour)
    01000 {
    01001         return (Colour->nRed << 11) | (Colour->nGreen << 5) | (Colour->nBlue);
    01002 }
    01003
    01004
    01005 ILushort Color888ToShort(Color888 *Colour)
    01006 {
    01007         return ((Colour->r >> 3) << 11) | ((Colour->g >> 2) << 5) | (Colour->b >> 3);
    01008 }
    01009
    01010
    01011 ILuint GenBitMask(ILushort ex0, ILushort ex1, ILuint NumCols, ILushort *In, ILubyte *Alpha, Color888 *OutCol)
    01012 {
    01013         ILuint          i, j, Closest, Dist, BitMask = 0;
    01014         ILubyte         Mask[16];
    01015         Color888        c, Colours[4];
    01016
    01017         ShortToColor888(ex0, &Colours[0]);
    01018         ShortToColor888(ex1, &Colours[1]);
    01019         if (NumCols == 3) {
    01020                 Colours[2].r = (Colours[0].r + Colours[1].r) / 2;
    01021                 Colours[2].g = (Colours[0].g + Colours[1].g) / 2;
    01022                 Colours[2].b = (Colours[0].b + Colours[1].b) / 2;
    01023                 Colours[3].r = (Colours[0].r + Colours[1].r) / 2;
    01024                 Colours[3].g = (Colours[0].g + Colours[1].g) / 2;
    01025                 Colours[3].b = (Colours[0].b + Colours[1].b) / 2;
    01026         }
    01027         else {  // NumCols == 4
    01028                 Colours[2].r = (2 * Colours[0].r + Colours[1].r + 1) / 3;
    01029                 Colours[2].g = (2 * Colours[0].g + Colours[1].g + 1) / 3;
    01030                 Colours[2].b = (2 * Colours[0].b + Colours[1].b + 1) / 3;
    01031                 Colours[3].r = (Colours[0].r + 2 * Colours[1].r + 1) / 3;
    01032                 Colours[3].g = (Colours[0].g + 2 * Colours[1].g + 1) / 3;
    01033                 Colours[3].b = (Colours[0].b + 2 * Colours[1].b + 1) / 3;
    01034         }
    01035
    01036         for (i = 0; i < 16; i++) {
    01037                 if (Alpha) {  // Test to see if we have 1-bit transparency
    01038                         if (Alpha[i] < 128) {
    01039                                 Mask[i] = 3;  // Transparent
    01040                                 if (OutCol) {
    01041                                         OutCol[i].r = Colours[3].r;
    01042                                         OutCol[i].g = Colours[3].g;
    01043                                         OutCol[i].b = Colours[3].b;
    01044                                 }
    01045                                 continue;
    01046                         }
    01047                 }
    01048
    01049                 // If no transparency, try to find which colour is the closest.
    01050                 Closest = UINT_MAX;
    01051                 ShortToColor888(In[i], &c);
    01052                 for (j = 0; j < NumCols; j++) {
    01053                         Dist = Distance(&c, &Colours[j]);
    01054                         if (Dist < Closest) {
    01055                                 Closest = Dist;
    01056                                 Mask[i] = j;
    01057                                 if (OutCol) {
    01058                                         OutCol[i].r = Colours[j].r;
    01059                                         OutCol[i].g = Colours[j].g;
    01060                                         OutCol[i].b = Colours[j].b;
    01061                                 }
    01062                         }
    01063                 }
    01064         }
    01065
    01066         for (i = 0; i < 16; i++) {
    01067                 BitMask |= (Mask[i] << (i*2));
    01068         }
    01069
    01070         return BitMask;
    01071 }
    01072
    01073
    01074 void GenAlphaBitMask(ILubyte a0, ILubyte a1, ILubyte *In, ILubyte *Mask, ILubyte *Out)
    01075 {
    01076         ILubyte Alphas[8], M[16];
    01077         ILuint  i, j, Closest, Dist;
    01078
    01079         Alphas[0] = a0;
    01080         Alphas[1] = a1;
    01081
    01082         // 8-alpha or 6-alpha block?
    01083         if (a0 > a1) {
    01084                 // 8-alpha block:  derive the other six alphas.
    01085                 // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
    01086                 Alphas[2] = (6 * Alphas[0] + 1 * Alphas[1] + 3) / 7;    // bit code 010
    01087                 Alphas[3] = (5 * Alphas[0] + 2 * Alphas[1] + 3) / 7;    // bit code 011
    01088                 Alphas[4] = (4 * Alphas[0] + 3 * Alphas[1] + 3) / 7;    // bit code 100
    01089                 Alphas[5] = (3 * Alphas[0] + 4 * Alphas[1] + 3) / 7;    // bit code 101
    01090                 Alphas[6] = (2 * Alphas[0] + 5 * Alphas[1] + 3) / 7;    // bit code 110
    01091                 Alphas[7] = (1 * Alphas[0] + 6 * Alphas[1] + 3) / 7;    // bit code 111
    01092         }
    01093         else {
    01094                 // 6-alpha block.
    01095                 // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
    01096                 Alphas[2] = (4 * Alphas[0] + 1 * Alphas[1] + 2) / 5;    // Bit code 010
    01097                 Alphas[3] = (3 * Alphas[0] + 2 * Alphas[1] + 2) / 5;    // Bit code 011
    01098                 Alphas[4] = (2 * Alphas[0] + 3 * Alphas[1] + 2) / 5;    // Bit code 100
    01099                 Alphas[5] = (1 * Alphas[0] + 4 * Alphas[1] + 2) / 5;    // Bit code 101
    01100                 Alphas[6] = 0x00;                                                                               // Bit code 110
    01101                 Alphas[7] = 0xFF;                                                                               // Bit code 111
    01102         }
    01103
    01104         for (i = 0; i < 16; i++) {
    01105                 Closest = UINT_MAX;
    01106                 for (j = 0; j < 8; j++) {
    01107                         Dist = abs((ILint)In[i] - (ILint)Alphas[j]);
    01108                         if (Dist < Closest) {
    01109                                 Closest = Dist;
    01110                                 M[i] = j;
    01111                         }
    01112                 }
    01113         }
    01114
    01115         if (Out) {
    01116                 for (i = 0; i < 16; i++) {
    01117                         Out[i] = Alphas[M[i]];
    01118                 }
    01119         }
    01120
    01121         //this was changed 20040623. There was a shift bug in here. Now the code
    01122         //produces much higher quality images.
    01123         // First three bytes.
    01124         Mask[0] = (M[0]) | (M[1] << 3) | ((M[2] & 0x03) << 6);
    01125         Mask[1] = ((M[2] & 0x04) >> 2) | (M[3] << 1) | (M[4] << 4) | ((M[5] & 0x01) << 7);
    01126         Mask[2] = ((M[5] & 0x06) >> 1) | (M[6] << 2) | (M[7] << 5);
    01127
    01128         // Second three bytes.
    01129         Mask[3] = (M[8]) | (M[9] << 3) | ((M[10] & 0x03) << 6);
    01130         Mask[4] = ((M[10] & 0x04) >> 2) | (M[11] << 1) | (M[12] << 4) | ((M[13] & 0x01) << 7);
    01131         Mask[5] = ((M[13] & 0x06) >> 1) | (M[14] << 2) | (M[15] << 5);
    01132
    01133         return;
    01134 }
    01135
    01136
    01137 ILuint RMSAlpha(ILubyte *Orig, ILubyte *Test)
    01138 {
    01139         ILuint  RMS = 0, i;
    01140         ILint   d;
    01141
    01142         for (i = 0; i < 16; i++) {
    01143                 d = Orig[i] - Test[i];
    01144                 RMS += d*d;
    01145         }
    01146
    01147         //RMS /= 16;
    01148
    01149         return RMS;
    01150 }
    01151
    01152
    01153 ILuint Distance(Color888 *c1, Color888 *c2)
    01154 {
    01155         return  (c1->r - c2->r) * (c1->r - c2->r) +
    01156                         (c1->g - c2->g) * (c1->g - c2->g) +
    01157                         (c1->b - c2->b) * (c1->b - c2->b);
    01158 }
    01159
    01160 #define Sum(c) ((c)->r + (c)->g + (c)->b)
    01161 #define NormSquared(c) ((c)->r * (c)->r + (c)->g * (c)->g + (c)->b * (c)->b)
    01162
    01163 void ChooseEndpoints(ILushort *Block, ILushort *ex0, ILushort *ex1)
    01164 {
    01165         ILuint          i;
    01166         Color888        Colours[16];
    01167         ILint           Lowest=0, Highest=0;
    01168
    01169         for (i = 0; i < 16; i++) {
    01170                 ShortToColor888(Block[i], &Colours[i]);
    01171
    01172                 if (NormSquared(&Colours[i]) < NormSquared(&Colours[Lowest]))
    01173                         Lowest = i;
    01174                 if (NormSquared(&Colours[i]) > NormSquared(&Colours[Highest]))
    01175                         Highest = i;
    01176         }
    01177         *ex0 = Block[Highest];
    01178         *ex1 = Block[Lowest];
    01179 }
    01180
    01181 #undef Sum
    01182 #undef NormSquared
    01183
    01184
    01185 void ChooseAlphaEndpoints(ILubyte *Block, ILubyte *a0, ILubyte *a1)
    01186 {
    01187         ILuint  i, Lowest = 0xFF, Highest = 0;
    01188
    01189         for (i = 0; i < 16; i++) {
    01190                 if (Block[i] < Lowest)
    01191                         Lowest = Block[i];
    01192                 if (Block[i] > Highest)
    01193                         Highest = Block[i];
    01194         }
    01195
    01196         *a0 = Lowest;
    01197         *a1 = Highest;
    01198 }
    01199
    01200
    01201 void CorrectEndDXT1(ILushort *ex0, ILushort *ex1, ILboolean HasAlpha)
    01202 {
    01203         ILushort Temp;
    01204
    01205         if (HasAlpha) {
    01206                 if (*ex0 > *ex1) {
    01207                         Temp = *ex0;
    01208                         *ex0 = *ex1;
    01209                         *ex1 = Temp;
    01210                 }
    01211         }
    01212         else {
    01213                 if (*ex0 < *ex1) {
    01214                         Temp = *ex0;
    01215                         *ex0 = *ex1;
    01216                         *ex1 = Temp;
    01217                 }
    01218         }
    01219
    01220         return;
    01221 }
    01222
    01223
    01224 void PreMult(ILushort *Data, ILubyte *Alpha)
    01225 {
    01226         Color888        Colour;
    01227         ILuint          i;
    01228
    01229         for (i = 0; i < 16; i++) {
    01230                 ShortToColor888(Data[i], &Colour);
    01231                 Colour.r = (ILubyte)(((ILuint)Colour.r * Alpha[i]) >> 8);
    01232                 Colour.g = (ILubyte)(((ILuint)Colour.g * Alpha[i]) >> 8);
    01233                 Colour.b = (ILubyte)(((ILuint)Colour.b * Alpha[i]) >> 8);
    01234
    01235                 /*Colour.r = (ILubyte)(Colour.r * (Alpha[i] / 255.0));
    01236                 Colour.g = (ILubyte)(Colour.g * (Alpha[i] / 255.0));
    01237                 Colour.b = (ILubyte)(Colour.b * (Alpha[i] / 255.0));*/
    01238
    01239                 Data[i] = Color888ToShort(&Colour);
    01240                 ShortToColor888(Data[i], &Colour);
    01241         }
    01242
    01243         return;
    01244 }
    01245
    01246
    01248 //  The data must be in unsigned byte RGBA or BGRA format.  Only DXT1, DXT3 and DXT5 are supported.
    01249 ILAPI ILubyte* ILAPIENTRY ilCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DXTCFormat, ILuint *DXTCSize)
    01250 {
    01251         ILimage *TempImage, *CurImage = iCurImage;
    01252         ILuint  BuffSize;
    01253         ILubyte *Buffer;
    01254
    01255         if ((DXTCFormat != IL_DXT1 && DXTCFormat != IL_DXT1A && DXTCFormat != IL_DXT3 && DXTCFormat != IL_DXT5)
    01256                 || Data == NULL || Width == 0 || Height == 0 || Depth == 0) {
    01257                 ilSetError(IL_INVALID_PARAM);
    01258                 return NULL;
    01259         }
    01260
    01261         // We want to try nVidia compression first, because it is the fastest.
    01262 #ifdef IL_USE_DXTC_NVIDIA
    01263         if (ilIsEnabled(IL_NVIDIA_COMPRESS) && Depth == 1) {  // See if we need to use the nVidia Texture Tools library.
    01264                 // NVTT needs data as BGRA 32-bit.
    01265                 // Here's where all the compression and writing goes on.
    01266                 return ilNVidiaCompressDXT(Data, Width, Height, 1, DXTCFormat, DXTCSize);
    01267         }
    01268 #endif//IL_USE_DXTC_NVIDIA
    01269
    01270         // libsquish generates better quality output than DevIL does, so we try it next.
    01271 #ifdef IL_USE_DXTC_SQUISH
    01272         if (ilIsEnabled(IL_SQUISH_COMPRESS) && Depth == 1) {  // See if we need to use the nVidia Texture Tools library.
    01273                 if (DXTCFormat == IL_DXT1 || DXTCFormat == IL_DXT1A || DXTCFormat == IL_DXT3 || DXTCFormat == IL_DXT5) {
    01274                         // libsquish needs data as RGBA 32-bit.
    01275                         // Get compressed data here.
    01276                         return ilSquishCompressDXT(Data, Width, Height, 1, DXTCFormat, DXTCSize);
    01277                 }
    01278         }
    01279 #endif//IL_USE_DXTC_SQUISH
    01280
    01281         TempImage = (ILimage*)ialloc(sizeof(ILimage));
    01282         memset(TempImage, 0, sizeof(ILimage));
    01283         TempImage->Width = Width;
    01284         TempImage->Height = Height;
    01285         TempImage->Depth = Depth;
    01286         TempImage->Bpp = 4;  // RGBA or BGRA
    01287         TempImage->Format = IL_BGRA;
    01288         TempImage->Bpc = 1;  // Unsigned bytes only
    01289         TempImage->Type = IL_UNSIGNED_BYTE;
    01290         TempImage->SizeOfPlane = TempImage->Bps * Height;
    01291         TempImage->SizeOfData  = TempImage->SizeOfPlane * Depth;
    01292         TempImage->Origin = IL_ORIGIN_UPPER_LEFT;
    01293         TempImage->Data = Data;
    01294
    01295         BuffSize = ilGetDXTCData(NULL, 0, DXTCFormat);
    01296         if (BuffSize == 0)
    01297                 return NULL;
    01298         Buffer = (ILubyte*)ialloc(BuffSize);
    01299         if (Buffer == NULL)
    01300                 return NULL;
    01301
    01302         if (ilGetDXTCData(Buffer, BuffSize, DXTCFormat) != BuffSize) {
    01303                 ifree(Buffer);
    01304                 return NULL;
    01305         }
    01306         *DXTCSize = BuffSize;
    01307
    01308         // Restore backup of iCurImage.
    01309         iCurImage = CurImage;
    01310         TempImage->Data = NULL;
    01311         ilCloseImage(TempImage);
    01312
    01313         return Buffer;
    01314 }