- Main Page
- Data Structures
- Files

- File List

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

    00001 //-----------------------------------------------------------------------------
    00002 //
    00003 // ImageLib Sources
    00004 // Copyright (C) 2000-2009 by Denton Woods
    00005 // Last modified: 01/30/2009
    00006 //
    00007 // Filename: src-IL/src/il_dds.c
    00008 //
    00009 // Description: Reads from a DirectDraw Surface (.dds) file.
    00010 //
    00011 //-----------------------------------------------------------------------------
    00012
    00013
    00014 //
    00015 //
    00016 // Note:  Almost all this code is from nVidia's DDS-loading example at
    00017 //      http://www.nvidia.com/view.asp?IO=dxtc_decompression_code
    00018 //      and from the specs at
    00019 //      http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dx8_c/hh/dx8_c/graphics_using_0j03.asp
    00020 //      and
    00021 //      http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dx8_c/directx_cpp/Graphics/ProgrammersGuide/Appendix/DDSFileFormat/ovwDDSFileFormat.asp
    00022 //      However, some not really valid .dds files are also read, for example
    00023 //      Volume Textures without the COMPLEX bit set, so the specs aren't taken
    00024 //      too strictly while reading.
    00025
    00026
    00027 #include "il_internal.h"
    00028 #ifndef IL_NO_DDS
    00029 #include "il_dds.h"
    00030
    00031
    00032 // Global variables
    00033 static DDSHEAD  Head;                           // Image header
    00034 static ILubyte  *CompData = NULL;       // Compressed data
    00035 static ILuint   CompSize;                       // Compressed size
    00036 static ILuint   CompFormat;                     // Compressed format
    00037 static ILimage  *Image;
    00038 static ILint    Width, Height, Depth;
    00039
    00040 ILuint CubemapDirections[CUBEMAP_SIDES] = {
    00041         DDS_CUBEMAP_POSITIVEX,
    00042         DDS_CUBEMAP_NEGATIVEX,
    00043         DDS_CUBEMAP_POSITIVEY,
    00044         DDS_CUBEMAP_NEGATIVEY,
    00045         DDS_CUBEMAP_POSITIVEZ,
    00046         DDS_CUBEMAP_NEGATIVEZ
    00047 };
    00048
    00049
    00051 ILboolean ilIsValidDds(ILconst_string FileName)
    00052 {
    00053         ILHANDLE        DdsFile;
    00054         ILboolean       bDds = IL_FALSE;
    00055
    00056         if (!iCheckExtension(FileName, IL_TEXT("dds"))) {
    00057                 ilSetError(IL_INVALID_EXTENSION);
    00058                 return bDds;
    00059         }
    00060
    00061         DdsFile = iopenr(FileName);
    00062         if (DdsFile == NULL) {
    00063                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00064                 return bDds;
    00065         }
    00066
    00067         bDds = ilIsValidDdsF(DdsFile);
    00068         icloser(DdsFile);
    00069
    00070         return bDds;
    00071 }
    00072
    00073
    00075 ILboolean ilIsValidDdsF(ILHANDLE File)
    00076 {
    00077         ILuint          FirstPos;
    00078         ILboolean       bRet;
    00079
    00080         iSetInputFile(File);
    00081         FirstPos = itell();
    00082         bRet = iIsValidDds();
    00083         iseek(FirstPos, IL_SEEK_SET);
    00084
    00085         return bRet;
    00086 }
    00087
    00088
    00090 ILboolean ilIsValidDdsL(const void *Lump, ILuint Size)
    00091 {
    00092         iSetInputLump(Lump, Size);
    00093         return iIsValidDds();
    00094 }
    00095
    00096
    00097 // Internal function used to get the .dds header from the current file.
    00098 ILboolean iGetDdsHead(DDSHEAD *Header)
    00099 {
    00100         ILint i;
    00101
    00102         iread(&Header->Signature, 1, 4);
    00103         Header->Size1 = GetLittleUInt();
    00104         Header->Flags1 = GetLittleUInt();
    00105         Header->Height = GetLittleUInt();
    00106         Header->Width = GetLittleUInt();
    00107         Header->LinearSize = GetLittleUInt();
    00108         Header->Depth = GetLittleUInt();
    00109         Header->MipMapCount = GetLittleUInt();
    00110         Header->AlphaBitDepth = GetLittleUInt();
    00111
    00112         for (i = 0; i < 10; ++i)
    00113                 Header->NotUsed[i] = GetLittleUInt();
    00114
    00115         Header->Size2 = GetLittleUInt();
    00116         Header->Flags2 = GetLittleUInt();
    00117         Header->FourCC = GetLittleUInt();
    00118         Header->RGBBitCount = GetLittleUInt();
    00119         Header->RBitMask = GetLittleUInt();
    00120         Header->GBitMask = GetLittleUInt();
    00121         Header->BBitMask = GetLittleUInt();
    00122         Header->RGBAlphaBitMask = GetLittleUInt();
    00123         Header->ddsCaps1 = GetLittleUInt();
    00124         Header->ddsCaps2 = GetLittleUInt();
    00125         Header->ddsCaps3 = GetLittleUInt();
    00126         Header->ddsCaps4 = GetLittleUInt();
    00127         Header->TextureStage = GetLittleUInt();
    00128
    00129         if (Head.Depth == 0)
    00130                 Head.Depth = 1;
    00131
    00132         return IL_TRUE;
    00133 }
    00134
    00135
    00136 // Internal function to get the header and check it.
    00137 ILboolean iIsValidDds()
    00138 {
    00139         ILboolean       IsValid;
    00140         DDSHEAD         Head;
    00141
    00142         iGetDdsHead(&Head);
    00143         iseek(-(ILint)sizeof(DDSHEAD), IL_SEEK_CUR);  // Go ahead and restore to previous state
    00144
    00145         IsValid = iCheckDds(&Head);
    00146
    00147         return IsValid;
    00148 }
    00149
    00150
    00151 // Internal function used to check if the HEADER is a valid .dds header.
    00152 ILboolean iCheckDds(DDSHEAD *Head)
    00153 {
    00154         if (strncmp((const char*)Head->Signature, "DDS ", 4))
    00155                 return IL_FALSE;
    00156         //note that if Size1 is "DDS " this is not a valid dds file according
    00157         //to the file spec. Some broken tool out there seems to produce files
    00158         //with this value in the size field, so we support reading them...
    00159         if (Head->Size1 != 124 && Head->Size1 != IL_MAKEFOURCC('D', 'D', 'S', ' '))
    00160                 return IL_FALSE;
    00161         if (Head->Size2 != 32)
    00162                 return IL_FALSE;
    00163         if (Head->Width == 0 || Head->Height == 0)
    00164                 return IL_FALSE;
    00165         return IL_TRUE;
    00166 }
    00167
    00168
    00170 ILboolean ilLoadDds(ILconst_string FileName)
    00171 {
    00172         ILHANDLE        DdsFile;
    00173         ILboolean       bDds = IL_FALSE;
    00174
    00175         DdsFile = iopenr(FileName);
    00176         if (DdsFile == NULL) {
    00177                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00178                 return bDds;
    00179         }
    00180
    00181         bDds = ilLoadDdsF(DdsFile);
    00182         icloser(DdsFile);
    00183
    00184         return bDds;
    00185 }
    00186
    00187
    00189 ILboolean ilLoadDdsF(ILHANDLE File)
    00190 {
    00191         ILuint          FirstPos;
    00192         ILboolean       bRet;
    00193
    00194         iSetInputFile(File);
    00195         FirstPos = itell();
    00196         bRet = iLoadDdsInternal();
    00197         iseek(FirstPos, IL_SEEK_SET);
    00198
    00199         return bRet;
    00200 }
    00201
    00202
    00204 ILboolean ilLoadDdsL(const void *Lump, ILuint Size)
    00205 {
    00206         iSetInputLump(Lump, Size);
    00207         return iLoadDdsInternal();
    00208 }
    00209
    00210
    00211 ILubyte iCompFormatToBpp(ILenum Format)
    00212 {
    00213         //non-compressed (= non-FOURCC) codes
    00214         if (Format == PF_LUMINANCE || Format == PF_LUMINANCE_ALPHA || Format == PF_ARGB)
    00215                 return Head.RGBBitCount/8;
    00216
    00217         //fourcc formats
    00218         else if (Format == PF_RGB || Format == PF_3DC || Format == PF_RXGB)
    00219                 return 3;
    00220         else if (Format == PF_ATI1N)
    00221                 return 1;
    00222         else if (Format == PF_R16F)
    00223                 return 2;
    00224         else if (Format == PF_A16B16G16R16 || Format == PF_A16B16G16R16F
    00225                 || Format == PF_G32R32F)
    00226                 return 8;
    00227         else if (Format == PF_A32B32G32R32F)
    00228                 return 16;
    00229         else //if (Format == PF_G16R16F || Format == PF_R32F || dxt)
    00230                 return 4;
    00231 }
    00232
    00233
    00234 ILubyte iCompFormatToBpc(ILenum Format)
    00235 {
    00236         if (Format == PF_R16F || Format == PF_G16R16F || Format == PF_A16B16G16R16F)
    00237                 //DevIL has no internal half type, so these formats are converted to 32 bits
    00238                 return 4;
    00239         else if (Format == PF_R32F || Format == PF_G32R32F || Format == PF_A32B32G32R32F)
    00240                 return 4;
    00241         else if(Format == PF_A16B16G16R16)
    00242                 return 2;
    00243         else
    00244                 return 1;
    00245 }
    00246
    00247
    00248 ILubyte iCompFormatToChannelCount(ILenum Format)
    00249 {
    00250         if (Format == PF_RGB || Format == PF_3DC || Format == PF_RXGB)
    00251                 return 3;
    00252         else if (Format == PF_LUMINANCE || Format == PF_R16F || Format == PF_R32F || Format == PF_ATI1N)
    00253                 return 1;
    00254         else if (Format == PF_LUMINANCE_ALPHA || Format == PF_G16R16F || Format == PF_G32R32F)
    00255                 return 2;
    00256         else //if(Format == PF_ARGB || dxt)
    00257                 return 4;
    00258 }
    00259
    00260
    00261 ILboolean iLoadDdsCubemapInternal()
    00262 {
    00263         ILuint  i;
    00264         ILubyte Bpp, Channels, Bpc;
    00265         ILimage *startImage;
    00266
    00267         CompData = NULL;
    00268
    00269         Bpp = iCompFormatToBpp(CompFormat);
    00270         Channels = iCompFormatToChannelCount(CompFormat);
    00271         Bpc = iCompFormatToBpc(CompFormat);
    00272         if (CompFormat == PF_LUMINANCE && Head.RGBBitCount == 16 && Head.RBitMask == 0xFFFF) { //@TODO: This is a HACK.
    00273                 Bpc = 2; Bpp = 2;
    00274         }
    00275
    00276         startImage = Image;
    00277         // Run through cube map possibilities
    00278         for (i = 0; i < CUBEMAP_SIDES; i++) {
    00279                 // Reset each time
    00280                 Width = Head.Width;
    00281                 Height = Head.Height;
    00282                 Depth = Head.Depth;
    00283                 if (Head.ddsCaps2 & CubemapDirections[i]) {
    00284                         if (i != 0) {
    00285                                 Image->Faces = ilNewImage(Width, Height, Depth, Channels, Bpc);
    00286                                 if (Image->Faces == NULL)
    00287                                         return IL_FALSE;
    00288
    00289                                 Image = Image->Faces;
    00290
    00291                                 if (CompFormat == PF_R16F
    00292                                         || CompFormat == PF_G16R16F
    00293                                         || CompFormat == PF_A16B16G16R16F
    00294                                         || CompFormat == PF_R32F
    00295                                         || CompFormat == PF_G32R32F
    00296                                         || CompFormat == PF_A32B32G32R32F) {
    00297                                         // DevIL's format autodetection doesn't work for
    00298                                         //  float images...correct this.
    00299                                         Image->Type = IL_FLOAT;
    00300                                         Image->Bpp = Channels;
    00301                                 }
    00302
    00303                                 ilBindImage(ilGetCurName()); // Set to parent image first.
    00304                                 //ilActiveImage(i); //@TODO: now Image == iCurImage...globals SUCK, fix this!!!
    00305                                 ilActiveFace(i);
    00306                         }
    00307
    00308                         if (!ReadData())
    00309                                 return IL_FALSE;
    00310
    00311                         if (!AllocImage()) {
    00312                                 if (CompData) {
    00313                                         ifree(CompData);
    00314                                         CompData = NULL;
    00315                                 }
    00316                                 return IL_FALSE;
    00317                         }
    00318
    00319                         Image->CubeFlags = CubemapDirections[i];
    00320
    00321                         if (!Decompress()) {
    00322                                 if (CompData) {
    00323                                         ifree(CompData);
    00324                                         CompData = NULL;
    00325                                 }
    00326                                 return IL_FALSE;
    00327                         }
    00328
    00329                         if (!ReadMipmaps()) {
    00330                                 if (CompData) {
    00331                                         ifree(CompData);
    00332                                         CompData = NULL;
    00333                                 }
    00334                                 return IL_FALSE;
    00335                         }
    00336                 }
    00337         }
    00338
    00339         if (CompData) {
    00340                 ifree(CompData);
    00341                 CompData = NULL;
    00342         }
    00343
    00344         ilBindImage(ilGetCurName());  // Set to parent image first.
    00345         return ilFixImage();
    00346 }
    00347
    00348
    00349 ILboolean iLoadDdsInternal()
    00350 {
    00351         ILuint BlockSize = 0;
    00352
    00353         CompData = NULL;
    00354         Image = NULL;
    00355
    00356         if (iCurImage == NULL) {
    00357                 ilSetError(IL_ILLEGAL_OPERATION);
    00358                 return IL_FALSE;
    00359         }
    00360
    00361         if (!iGetDdsHead(&Head)) {
    00362                 ilSetError(IL_INVALID_FILE_HEADER);
    00363                 return IL_FALSE;
    00364         }
    00365         if (!iCheckDds(&Head)) {
    00366                 ilSetError(IL_INVALID_FILE_HEADER);
    00367                 return IL_FALSE;
    00368         }
    00369
    00370         BlockSize = DecodePixelFormat();
    00371         if (CompFormat == PF_UNKNOWN) {
    00372                 ilSetError(IL_INVALID_FILE_HEADER);
    00373                 return IL_FALSE;
    00374         }
    00375
    00376         // Microsoft bug, they're not following their own documentation.
    00377         if (!(Head.Flags1 & (DDS_LINEARSIZE | DDS_PITCH))
    00378                 || Head.LinearSize == 0) {
    00379                 Head.Flags1 |= DDS_LINEARSIZE;
    00380                 Head.LinearSize = BlockSize;
    00381         }
    00382
    00383         Image = iCurImage;
    00384         if (Head.ddsCaps1 & DDS_COMPLEX) {
    00385                 if (Head.ddsCaps2 & DDS_CUBEMAP) {
    00386                         if (!iLoadDdsCubemapInternal())
    00387                                 return IL_FALSE;
    00388                         return IL_TRUE;
    00389                 }
    00390         }
    00391
    00392         Width = Head.Width;
    00393         Height = Head.Height;
    00394         Depth = Head.Depth;
    00395         AdjustVolumeTexture(&Head);
    00396
    00397         if (!ReadData())
    00398                 return IL_FALSE;
    00399         if (!AllocImage()) {
    00400                 if (CompData) {
    00401                         ifree(CompData);
    00402                         CompData = NULL;
    00403                 }
    00404                 return IL_FALSE;
    00405         }
    00406         if (!Decompress()) {
    00407                 if (CompData) {
    00408                         ifree(CompData);
    00409                         CompData = NULL;
    00410                 }
    00411                 return IL_FALSE;
    00412         }
    00413
    00414         if (!ReadMipmaps()) {
    00415                 if (CompData) {
    00416                         ifree(CompData);
    00417                         CompData = NULL;
    00418                 }
    00419                 return IL_FALSE;
    00420         }
    00421
    00422         if (CompData) {
    00423                 ifree(CompData);
    00424                 CompData = NULL;
    00425         }
    00426
    00427         ilBindImage(ilGetCurName());  // Set to parent image first.
    00428         return ilFixImage();
    00429 }
    00430
    00431
    00432 ILuint DecodePixelFormat()
    00433 {
    00434         ILuint BlockSize;
    00435
    00436         if (Head.Flags2 & DDS_FOURCC) {
    00437                 BlockSize = ((Head.Width + 3)/4) * ((Head.Height + 3)/4) * Head.Depth;
    00438                 switch (Head.FourCC)
    00439                 {
    00440                         case IL_MAKEFOURCC('D','X','T','1'):
    00441                                 CompFormat = PF_DXT1;
    00442                                 BlockSize *= 8;
    00443                                 break;
    00444
    00445                         case IL_MAKEFOURCC('D','X','T','2'):
    00446                                 CompFormat = PF_DXT2;
    00447                                 BlockSize *= 16;
    00448                                 break;
    00449
    00450                         case IL_MAKEFOURCC('D','X','T','3'):
    00451                                 CompFormat = PF_DXT3;
    00452                                 BlockSize *= 16;
    00453                                 break;
    00454
    00455                         case IL_MAKEFOURCC('D','X','T','4'):
    00456                                 CompFormat = PF_DXT4;
    00457                                 BlockSize *= 16;
    00458                                 break;
    00459
    00460                         case IL_MAKEFOURCC('D','X','T','5'):
    00461                                 CompFormat = PF_DXT5;
    00462                                 BlockSize *= 16;
    00463                                 break;
    00464
    00465                         case IL_MAKEFOURCC('A', 'T', 'I', '1'):
    00466                                 CompFormat = PF_ATI1N;
    00467                                 BlockSize *= 8;
    00468                                 break;
    00469
    00470                         case IL_MAKEFOURCC('A', 'T', 'I', '2'):
    00471                                 CompFormat = PF_3DC;
    00472                                 BlockSize *= 16;
    00473                                 break;
    00474
    00475                         case IL_MAKEFOURCC('R', 'X', 'G', 'B'):
    00476                                 CompFormat = PF_RXGB;
    00477                                 BlockSize *= 16;
    00478                                 break;
    00479
    00480                         case IL_MAKEFOURCC('$', '\0', '\0', '\0'):
    00481                                 CompFormat = PF_A16B16G16R16;
    00482                                 BlockSize = Head.Width * Head.Height * Head.Depth * 8;
    00483                                 break;
    00484
    00485                         case IL_MAKEFOURCC('o', '\0', '\0', '\0'):
    00486                                 CompFormat = PF_R16F;
    00487                                 BlockSize = Head.Width * Head.Height * Head.Depth * 2;
    00488                                 break;
    00489
    00490                         case IL_MAKEFOURCC('p', '\0', '\0', '\0'):
    00491                                 CompFormat = PF_G16R16F;
    00492                                 BlockSize = Head.Width * Head.Height * Head.Depth * 4;
    00493                                 break;
    00494
    00495                         case IL_MAKEFOURCC('q', '\0', '\0', '\0'):
    00496                                 CompFormat = PF_A16B16G16R16F;
    00497                                 BlockSize = Head.Width * Head.Height * Head.Depth * 8;
    00498                                 break;
    00499
    00500                         case IL_MAKEFOURCC('r', '\0', '\0', '\0'):
    00501                                 CompFormat = PF_R32F;
    00502                                 BlockSize = Head.Width * Head.Height * Head.Depth * 4;
    00503                                 break;
    00504
    00505                         case IL_MAKEFOURCC('s', '\0', '\0', '\0'):
    00506                                 CompFormat = PF_G32R32F;
    00507                                 BlockSize = Head.Width * Head.Height * Head.Depth * 8;
    00508                                 break;
    00509
    00510                         case IL_MAKEFOURCC('t', '\0', '\0', '\0'):
    00511                                 CompFormat = PF_A32B32G32R32F;
    00512                                 BlockSize = Head.Width * Head.Height * Head.Depth * 16;
    00513                                 break;
    00514
    00515                         default:
    00516                                 CompFormat = PF_UNKNOWN;
    00517                                 BlockSize *= 16;
    00518                                 break;
    00519                 }
    00520         } else {
    00521                 // This dds texture isn't compressed so write out ARGB or luminance format
    00522                 if (Head.Flags2 & DDS_LUMINANCE) {
    00523                         if (Head.Flags2 & DDS_ALPHAPIXELS) {
    00524                                 CompFormat = PF_LUMINANCE_ALPHA;
    00525                         } else {
    00526                                 CompFormat = PF_LUMINANCE;
    00527                         }
    00528                 }
    00529                 else {
    00530                         if (Head.Flags2 & DDS_ALPHAPIXELS) {
    00531                                 CompFormat = PF_ARGB;
    00532                         } else {
    00533                                 CompFormat = PF_RGB;
    00534                         }
    00535                 }
    00536                 BlockSize = (Head.Width * Head.Height * Head.Depth * (Head.RGBBitCount >> 3));
    00537         }
    00538
    00539         return BlockSize;
    00540 }
    00541
    00542
    00543 // The few volume textures that I have don't have consistent LinearSize
    00544 //      entries, even though the DDS_LINEARSIZE flag is set.
    00545 void AdjustVolumeTexture(DDSHEAD *Head)
    00546 {
    00547         if (Head->Depth <= 1)
    00548                 return;
    00549
    00550         // All volume textures I've seem so far didn't have the DDS_COMPLEX flag set,
    00551         // even though this is normally required. But because noone does set it,
    00552         // also read images without it (TODO: check file size for 3d texture?)
    00553         if ( !(Head->ddsCaps2 & DDS_VOLUME)) {
    00554                 Head->Depth = 1;
    00555                 Depth = 1;
    00556         }
    00557
    00558         switch (CompFormat)
    00559         {
    00560                 case PF_ARGB:
    00561                 case PF_RGB:
    00562                 case PF_LUMINANCE:
    00563                 case PF_LUMINANCE_ALPHA:
    00564                         //don't use the iCompFormatToBpp() function because this way
    00565                         //argb images with only 8 bits (eg. a1r2g3b2) work as well
    00566                         Head->LinearSize = IL_MAX(1,Head->Width) * IL_MAX(1,Head->Height) *
    00567                                 (Head->RGBBitCount / 8);
    00568                         break;
    00569
    00570                 case PF_DXT1:
    00571
    00572                 case PF_ATI1N:
    00573                         Head->LinearSize = ((Head->Width+3)/4) * ((Head->Height+3)/4) * 8;
    00574                         break;
    00575
    00576                 case PF_DXT2:
    00577                 case PF_DXT3:
    00578                 case PF_DXT4:
    00579                 case PF_DXT5:
    00580                 case PF_3DC:
    00581                 case PF_RXGB:
    00582                         Head->LinearSize = ((Head->Width+3)/4) * ((Head->Height+3)/4) * 16;
    00583                         break;
    00584
    00585                 case PF_A16B16G16R16:
    00586                 case PF_R16F:
    00587                 case PF_G16R16F:
    00588                 case PF_A16B16G16R16F:
    00589                 case PF_R32F:
    00590                 case PF_G32R32F:
    00591                 case PF_A32B32G32R32F:
    00592                         Head->LinearSize = IL_MAX(1,Head->Width) * IL_MAX(1,Head->Height) *
    00593                                 iCompFormatToBpp(CompFormat);
    00594                         break;
    00595         }
    00596
    00597         Head->Flags1 |= DDS_LINEARSIZE;
    00598         Head->LinearSize *= Head->Depth;
    00599
    00600         return;
    00601 }
    00602
    00603
    00604 // Reads the compressed data
    00605 ILboolean ReadData()
    00606 {
    00607         ILuint  Bps;
    00608         ILint   y, z;
    00609         ILubyte *Temp;
    00610
    00611         if (CompData) {
    00612                 ifree(CompData);
    00613                 CompData = NULL;
    00614         }
    00615
    00616         if (Head.Flags1 & DDS_LINEARSIZE) {
    00617                 //Head.LinearSize = Head.LinearSize * Depth;
    00618
    00619                 CompData = (ILubyte*)ialloc(Head.LinearSize);
    00620                 if (CompData == NULL) {
    00621                         return IL_FALSE;
    00622                 }
    00623
    00624                 if (iread(CompData, 1, Head.LinearSize) != (ILuint)Head.LinearSize) {
    00625                         ifree(CompData);
    00626                         CompData = NULL;
    00627                         return IL_FALSE;
    00628                 }
    00629         }
    00630         else {
    00631                 Bps = Width * Head.RGBBitCount / 8;
    00632                 CompSize = Bps * Height * Depth;
    00633
    00634                 CompData = (ILubyte*)ialloc(CompSize);
    00635                 if (CompData == NULL) {
    00636                         return IL_FALSE;
    00637                 }
    00638
    00639                 Temp = CompData;
    00640                 for (z = 0; z < Depth; z++) {
    00641                         for (y = 0; y < Height; y++) {
    00642                                 if (iread(Temp, 1, Bps) != Bps) {
    00643                                         ifree(CompData);
    00644                                         CompData = NULL;
    00645                                         return IL_FALSE;
    00646                                 }
    00647                                 Temp += Bps;
    00648                         }
    00649                 }
    00650         }
    00651
    00652         return IL_TRUE;
    00653 }
    00654
    00655
    00656 ILboolean AllocImage()
    00657 {
    00658         ILubyte channels = 4;
    00659         ILenum format = IL_RGBA;
    00660
    00661         switch (CompFormat)
    00662         {
    00663                 case PF_RGB:
    00664                         if (!ilTexImage(Width, Height, Depth, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
    00665                                 return IL_FALSE;
    00666                         break;
    00667                 case PF_ARGB:
    00668                         if (!ilTexImage(Width, Height, Depth, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL))
    00669                                 return IL_FALSE;
    00670                         break;
    00671
    00672                 case PF_LUMINANCE:
    00673                         if(Head.RGBBitCount == 16 && Head.RBitMask == 0xFFFF) { //HACK
    00674                                 if (!ilTexImage(Width, Height, Depth, 1, IL_LUMINANCE, IL_UNSIGNED_SHORT, NULL))
    00675                                         return IL_FALSE;
    00676                         }
    00677                         else
    00678                                 if (!ilTexImage(Width, Height, Depth, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL))
    00679                                         return IL_FALSE;
    00680                         break;
    00681
    00682                 case PF_LUMINANCE_ALPHA:
    00683                         if (!ilTexImage(Width, Height, Depth, 2, IL_LUMINANCE_ALPHA, IL_UNSIGNED_BYTE, NULL))
    00684                                 return IL_FALSE;
    00685                         break;
    00686
    00687                 case PF_ATI1N:
    00688                         //right now there's no OpenGL api to use the compressed 3dc data, so
    00689                         //throw it away (I don't know how DirectX works, though)?
    00690                         if (!ilTexImage(Width, Height, Depth, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL))
    00691                                 return IL_FALSE;
    00692                         break;
    00693
    00694                 case PF_3DC:
    00695                         //right now there's no OpenGL api to use the compressed 3dc data, so
    00696                         //throw it away (I don't know how DirectX works, though)?
    00697                         if (!ilTexImage(Width, Height, Depth, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
    00698                                 return IL_FALSE;
    00699                         break;
    00700
    00701                 case PF_A16B16G16R16:
    00702                         if (!ilTexImage(Width, Height, Depth, iCompFormatToChannelCount(CompFormat),
    00703                                 ilGetFormatBpp(iCompFormatToChannelCount(CompFormat)), IL_UNSIGNED_SHORT, NULL))
    00704                                 return IL_FALSE;
    00705                         break;
    00706
    00707                 case PF_R16F:
    00708                 case PF_G16R16F:
    00709                 case PF_A16B16G16R16F:
    00710                 case PF_R32F:
    00711                 case PF_G32R32F:
    00712                 case PF_A32B32G32R32F:
    00713                         if (!ilTexImage(Width, Height, Depth, iCompFormatToChannelCount(CompFormat),
    00714                                 ilGetFormatBpp(iCompFormatToChannelCount(CompFormat)), IL_FLOAT, NULL))
    00715                                 return IL_FALSE;
    00716                         break;
    00717
    00718                 default:
    00719                         if (CompFormat == PF_RXGB) {
    00720                                 channels = 3; //normal map
    00721                                 format = IL_RGB;
    00722                         }
    00723
    00724                         if (!ilTexImage(Width, Height, Depth, channels, format, IL_UNSIGNED_BYTE, NULL))
    00725                                 return IL_FALSE;
    00726                         if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE && CompData) {
    00727                                 iCurImage->DxtcData = (ILubyte*)ialloc(Head.LinearSize);
    00728                                 if (iCurImage->DxtcData == NULL)
    00729                                         return IL_FALSE;
    00730                                 iCurImage->DxtcFormat = CompFormat - PF_DXT1 + IL_DXT1;
    00731                                 iCurImage->DxtcSize = Head.LinearSize;
    00732                                 memcpy(iCurImage->DxtcData, CompData, iCurImage->DxtcSize);
    00733                         }
    00734                         break;
    00735         }
    00736
    00737         Image->Origin = IL_ORIGIN_UPPER_LEFT;
    00738
    00739         return IL_TRUE;
    00740 }
    00741
    00742
    00743 /*
    00744  * Assumes that the global variable CompFormat stores the format of the
    00745  * global pointer CompData (that's the pointer to the compressed data).
    00746  * Decompresses this data into Image->Data, returns if it was successful.
    00747  * It also uses the globals Width and Height.
    00748  *
    00749  * Assumes that iCurImage has valid Width, Height, Depth, Data, SizeOfData,
    00750  * Bpp, Bpc, Bps, SizeOfPlane, Format and Type fields. It is more or
    00751  * less assumed that the image has u8 rgba data (perhaps not for float
    00752  * images...)
    00753  *
    00754  *
    00755  * @TODO: don't use globals, clean this function (and this file) up
    00756  */
    00757 ILboolean Decompress()
    00758 {
    00759         switch (CompFormat)
    00760         {
    00761                 case PF_ARGB:
    00762                 case PF_RGB:
    00763                 case PF_LUMINANCE:
    00764                 case PF_LUMINANCE_ALPHA:
    00765                         return DecompressARGB();
    00766
    00767                 case PF_DXT1:
    00768                         return DecompressDXT1(Image, CompData);
    00769
    00770                 case PF_DXT2:
    00771                         return DecompressDXT2(Image, CompData);
    00772
    00773                 case PF_DXT3:
    00774                         return DecompressDXT3(Image, CompData);
    00775
    00776                 case PF_DXT4:
    00777                         return DecompressDXT4(Image, CompData);
    00778
    00779                 case PF_DXT5:
    00780                         return DecompressDXT5(Image, CompData);
    00781
    00782                 case PF_ATI1N:
    00783                         return DecompressAti1n();
    00784
    00785                 case PF_3DC:
    00786                         return Decompress3Dc();
    00787
    00788                 case PF_RXGB:
    00789                         return DecompressRXGB();
    00790
    00791                 case PF_A16B16G16R16:
    00792                         memcpy(Image->Data, CompData, Image->SizeOfData);
    00793                         return IL_TRUE;
    00794
    00795                 case PF_R16F:
    00796                 case PF_G16R16F:
    00797                 case PF_A16B16G16R16F:
    00798                 case PF_R32F:
    00799                 case PF_G32R32F:
    00800                 case PF_A32B32G32R32F:
    00801                         return DecompressFloat(CompFormat);
    00802
    00803                 case PF_UNKNOWN:
    00804                         return IL_FALSE;
    00805         }
    00806
    00807         return IL_FALSE;
    00808 }
    00809
    00810
    00811 ILboolean ReadMipmaps()
    00812 {
    00813         ILuint  i, CompFactor=0;
    00814         ILubyte Bpp, Channels, Bpc;
    00815         ILimage *StartImage, *TempImage;
    00816         ILuint  LastLinear;
    00817         ILuint  minW, minH;
    00818
    00819         ILboolean isCompressed = IL_FALSE;
    00820
    00821         Bpp = iCompFormatToBpp(CompFormat);
    00822         Channels = iCompFormatToChannelCount(CompFormat);
    00823         Bpc = iCompFormatToBpc(CompFormat);
    00824         if (CompFormat == PF_LUMINANCE && Head.RGBBitCount == 16 && Head.RBitMask == 0xFFFF) { //HACK
    00825                 Bpc = 2; Bpp = 2;
    00826         }
    00827
    00828         //This doesn't work for images which first mipmap (= the image
    00829         //itself) has width or height < 4
    00830         //if (Head.Flags1 & DDS_LINEARSIZE) {
    00831         //      CompFactor = (Width * Height * Depth * Bpp) / Head.LinearSize;
    00832         //}
    00833         switch (CompFormat)
    00834         {
    00835                 case PF_DXT1:
    00836                         //This is officially 6, we have 8 here because DXT1 may contain alpha
    00837                         CompFactor = 8;
    00838                         break;
    00839                 case PF_DXT2:
    00840                 case PF_DXT3:
    00841                 case PF_DXT4:
    00842                 case PF_DXT5:
    00843                         CompFactor = 4;
    00844                         break;
    00845                 case PF_RXGB:
    00846                 case PF_3DC:
    00847                         //This is officially 4 for 3dc, but that's bullshit :) There's no
    00848                         //alpha data in 3dc images
    00849                         CompFactor = 3;
    00850                         break;
    00851
    00852                 case PF_ATI1N:
    00853                         CompFactor = 2;
    00854                         break;
    00855                 default:
    00856                         CompFactor = 1;
    00857         }
    00858
    00859         StartImage = Image;
    00860
    00861         if (!(Head.Flags1 & DDS_MIPMAPCOUNT) || Head.MipMapCount == 0) {
    00862                 //some .dds-files have their mipmap flag set,
    00863                 //but a mipmapcount of 0. Because mipMapCount is an uint, 0 - 1 gives
    00864                 //overflow - don't let this happen:
    00865                 Head.MipMapCount = 1;
    00866         }
    00867
    00868         LastLinear = Head.LinearSize;
    00869         for (i = 0; i < Head.MipMapCount - 1; i++) {
    00870                 Depth = Depth / 2;
    00871                 Width = Width / 2;
    00872                 Height = Height / 2;
    00873
    00874                 if (Depth == 0)
    00875                         Depth = 1;
    00876                 if (Width == 0)
    00877                         Width = 1;
    00878                 if (Height == 0)
    00879                         Height = 1;
    00880
    00881                 Image->Mipmaps = ilNewImage(Width, Height, Depth, Channels, Bpc);
    00882                 if (Image->Mipmaps == NULL)
    00883                         goto mip_fail;
    00884                 Image = Image->Mipmaps;
    00885                 Image->Origin = IL_ORIGIN_UPPER_LEFT;
    00886
    00887                 if (Head.Flags1 & DDS_LINEARSIZE) {
    00888                         if (CompFormat == PF_R16F
    00889                                 || CompFormat == PF_G16R16F
    00890                                 || CompFormat == PF_A16B16G16R16F
    00891                                 || CompFormat == PF_R32F
    00892                                 || CompFormat == PF_G32R32F
    00893                                 || CompFormat == PF_A32B32G32R32F) {
    00894                                 Head.LinearSize = Width * Height * Depth * Bpp;
    00895
    00896                                 //DevIL's format autodetection doesn't work for
    00897                                 //float images...correct this
    00898                                 Image->Type = IL_FLOAT;
    00899                                 Image->Bpp = Channels;
    00900                         }
    00901                         else if (CompFormat == PF_A16B16G16R16)
    00902                                 Head.LinearSize = Width * Height * Depth * Bpp;
    00903                         else if (CompFormat != PF_RGB && CompFormat != PF_ARGB
    00904                                 && CompFormat != PF_LUMINANCE
    00905                                 && CompFormat != PF_LUMINANCE_ALPHA) {
    00906
    00907                                 //compressed format
    00908                                 minW = (((Width+3)/4))*4;
    00909                                 minH = (((Height+3)/4))*4;
    00910                                 Head.LinearSize = (minW * minH * Depth * Bpp) / CompFactor;
    00911
    00912                                 isCompressed = IL_TRUE;
    00913                         }
    00914                         else {
    00915                                 //don't use Bpp to support argb images with less than 32 bits
    00916                                 Head.LinearSize = Width * Height * Depth * (Head.RGBBitCount >> 3);
    00917                         }
    00918                 }
    00919                 else {
    00920                         Head.LinearSize >>= 1;
    00921                 }
    00922
    00923                 if (!ReadData())
    00924                         goto mip_fail;
    00925
    00926                 if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE && isCompressed == IL_TRUE && CompData) {
    00927                         Image->DxtcData = (ILubyte*)ialloc(Head.LinearSize);
    00928                         if (Image->DxtcData == NULL)
    00929                                 return IL_FALSE;
    00930                         Image->DxtcFormat = CompFormat - PF_DXT1 + IL_DXT1;
    00931                         Image->DxtcSize = Head.LinearSize;
    00932                         memcpy(Image->DxtcData, CompData, Image->DxtcSize);
    00933                 }
    00934
    00935                 if (!Decompress())
    00936                         goto mip_fail;
    00937         }
    00938
    00939         Head.LinearSize = LastLinear;
    00940         Image = StartImage;
    00941
    00942         return IL_TRUE;
    00943
    00944 mip_fail:
    00945         Image = StartImage;
    00946         StartImage = StartImage->Mipmaps;
    00947         while (StartImage) {
    00948                 TempImage = StartImage;
    00949                 StartImage = StartImage->Mipmaps;
    00950                 ifree(TempImage);
    00951         }
    00952
    00953         Image->Mipmaps = NULL;
    00954         return IL_FALSE;
    00955 }
    00956
    00957
    00958 void DxtcReadColors(const ILubyte* Data, Color8888* Out)
    00959 {
    00960         ILubyte r0, g0, b0, r1, g1, b1;
    00961
    00962         b0 = Data[0] & 0x1F;
    00963         g0 = ((Data[0] & 0xE0) >> 5) | ((Data[1] & 0x7) << 3);
    00964         r0 = (Data[1] & 0xF8) >> 3;
    00965
    00966         b1 = Data[2] & 0x1F;
    00967         g1 = ((Data[2] & 0xE0) >> 5) | ((Data[3] & 0x7) << 3);
    00968         r1 = (Data[3] & 0xF8) >> 3;
    00969
    00970         Out[0].r = r0 << 3 | r0 >> 2;
    00971         Out[0].g = g0 << 2 | g0 >> 3;
    00972         Out[0].b = b0 << 3 | b0 >> 2;
    00973
    00974         Out[1].r = r1 << 3 | r1 >> 2;
    00975         Out[1].g = g1 << 2 | g1 >> 3;
    00976         Out[1].b = b1 << 3 | b1 >> 2;
    00977 }
    00978
    00979 //@TODO: Probably not safe on Big Endian.
    00980 void DxtcReadColor(ILushort Data, Color8888* Out)
    00981 {
    00982         ILubyte r, g, b;
    00983
    00984         b = Data & 0x1f;
    00985         g = (Data & 0x7E0) >> 5;
    00986         r = (Data & 0xF800) >> 11;
    00987
    00988         Out->r = r << 3 | r >> 2;
    00989         Out->g = g << 2 | g >> 3;
    00990         Out->b = b << 3 | r >> 2;
    00991 }
    00992
    00993 ILboolean DecompressDXT1(ILimage *lImage, ILubyte *lCompData)
    00994 {
    00995         ILuint          x, y, z, i, j, k, Select;
    00996         ILubyte         *Temp;
    00997         Color8888       colours[4], *col;
    00998         ILushort        color_0, color_1;
    00999         ILuint          bitmask, Offset;
    01000
    01001         if (!lCompData)
    01002                 return IL_FALSE;
    01003
    01004         Temp = lCompData;
    01005         colours[0].a = 0xFF;
    01006         colours[1].a = 0xFF;
    01007         colours[2].a = 0xFF;
    01008         //colours[3].a = 0xFF;
    01009         for (z = 0; z < lImage->Depth; z++) {
    01010                 for (y = 0; y < lImage->Height; y += 4) {
    01011                         for (x = 0; x < lImage->Width; x += 4) {
    01012                                 color_0 = *((ILushort*)Temp);
    01013                                 UShort(&color_0);
    01014                                 color_1 = *((ILushort*)(Temp + 2));
    01015                                 UShort(&color_1);
    01016                                 DxtcReadColor(color_0, colours);
    01017                                 DxtcReadColor(color_1, colours + 1);
    01018                                 bitmask = ((ILuint*)Temp)[1];
    01019                                 UInt(&bitmask);
    01020                                 Temp += 8;
    01021
    01022                                 if (color_0 > color_1) {
    01023                                         // Four-color block: derive the other two colors.
    01024                                         // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
    01025                                         // These 2-bit codes correspond to the 2-bit fields
    01026                                         // stored in the 64-bit block.
    01027                                         colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
    01028                                         colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
    01029                                         colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
    01030                                         //colours[2].a = 0xFF;
    01031
    01032                                         colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
    01033                                         colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
    01034                                         colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
    01035                                         colours[3].a = 0xFF;
    01036                                 }
    01037                                 else {
    01038                                         // Three-color block: derive the other color.
    01039                                         // 00 = color_0,  01 = color_1,  10 = color_2,
    01040                                         // 11 = transparent.
    01041                                         // These 2-bit codes correspond to the 2-bit fields
    01042                                         // stored in the 64-bit block.
    01043                                         colours[2].b = (colours[0].b + colours[1].b) / 2;
    01044                                         colours[2].g = (colours[0].g + colours[1].g) / 2;
    01045                                         colours[2].r = (colours[0].r + colours[1].r) / 2;
    01046                                         //colours[2].a = 0xFF;
    01047
    01048                                         colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
    01049                                         colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
    01050                                         colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
    01051                                         colours[3].a = 0x00;
    01052                                 }
    01053
    01054                                 for (j = 0, k = 0; j < 4; j++) {
    01055                                         for (i = 0; i < 4; i++, k++) {
    01056                                                 Select = (bitmask & (0x03 << k*2)) >> k*2;
    01057                                                 col = &colours[Select];
    01058
    01059                                                 if (((x + i) < lImage->Width) && ((y + j) < lImage->Height)) {
    01060                                                         Offset = z * lImage->SizeOfPlane + (y + j) * lImage->Bps + (x + i) * lImage->Bpp;
    01061                                                         lImage->Data[Offset + 0] = col->r;
    01062                                                         lImage->Data[Offset + 1] = col->g;
    01063                                                         lImage->Data[Offset + 2] = col->b;
    01064                                                         lImage->Data[Offset + 3] = col->a;
    01065                                                 }
    01066                                         }
    01067                                 }
    01068                         }
    01069                 }
    01070         }
    01071
    01072         return IL_TRUE;
    01073 }
    01074
    01075
    01076 ILboolean DecompressDXT2(ILimage *lImage, ILubyte *lCompData)
    01077 {
    01078         // Can do color & alpha same as dxt3, but color is pre-multiplied
    01079         //   so the result will be wrong unless corrected.
    01080         if (!DecompressDXT3(Image, CompData))
    01081                 return IL_FALSE;
    01082         CorrectPreMult();
    01083
    01084         return IL_TRUE;
    01085 }
    01086
    01087
    01088 ILboolean DecompressDXT3(ILimage *lImage, ILubyte *lCompData)
    01089 {
    01090         ILuint          x, y, z, i, j, k, Select;
    01091         ILubyte         *Temp;
    01092         //Color565      *color_0, *color_1;
    01093         Color8888       colours[4], *col;
    01094         ILuint          bitmask, Offset;
    01095         ILushort        word;
    01096         ILubyte         *alpha;
    01097
    01098         if (!lCompData)
    01099                 return IL_FALSE;
    01100
    01101         Temp = lCompData;
    01102         for (z = 0; z < lImage->Depth; z++) {
    01103                 for (y = 0; y < lImage->Height; y += 4) {
    01104                         for (x = 0; x < lImage->Width; x += 4) {
    01105                                 alpha = Temp;
    01106                                 Temp += 8;
    01107                                 DxtcReadColors(Temp, colours);
    01108                                 bitmask = ((ILuint*)Temp)[1];
    01109                                 UInt(&bitmask);
    01110                                 Temp += 8;
    01111
    01112                                 // Four-color block: derive the other two colors.
    01113                                 // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
    01114                                 // These 2-bit codes correspond to the 2-bit fields
    01115                                 // stored in the 64-bit block.
    01116                                 colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
    01117                                 colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
    01118                                 colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
    01119                                 //colours[2].a = 0xFF;
    01120
    01121                                 colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
    01122                                 colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
    01123                                 colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
    01124                                 //colours[3].a = 0xFF;
    01125
    01126                                 k = 0;
    01127                                 for (j = 0; j < 4; j++) {
    01128                                         for (i = 0; i < 4; i++, k++) {
    01129                                                 Select = (bitmask & (0x03 << k*2)) >> k*2;
    01130                                                 col = &colours[Select];
    01131
    01132                                                 if (((x + i) < lImage->Width) && ((y + j) < lImage->Height)) {
    01133                                                         Offset = z * lImage->SizeOfPlane + (y + j) * lImage->Bps + (x + i) * lImage->Bpp;
    01134                                                         lImage->Data[Offset + 0] = col->r;
    01135                                                         lImage->Data[Offset + 1] = col->g;
    01136                                                         lImage->Data[Offset + 2] = col->b;
    01137                                                 }
    01138                                         }
    01139                                 }
    01140
    01141                                 for (j = 0; j < 4; j++) {
    01142                                         word = alpha[2*j] + 256*alpha[2*j+1];
    01143                                         for (i = 0; i < 4; i++) {
    01144                                                 if (((x + i) < lImage->Width) && ((y + j) < lImage->Height)) {
    01145                                                         Offset = z * lImage->SizeOfPlane + (y + j) * lImage->Bps + (x + i) * lImage->Bpp + 3;
    01146                                                         lImage->Data[Offset] = word & 0x0F;
    01147                                                         lImage->Data[Offset] = lImage->Data[Offset] | (lImage->Data[Offset] << 4);
    01148                                                 }
    01149                                                 word >>= 4;
    01150                                         }
    01151                                 }
    01152
    01153                         }
    01154                 }
    01155         }
    01156
    01157         return IL_TRUE;
    01158 }
    01159
    01160
    01161 ILboolean DecompressDXT4(ILimage *lImage, ILubyte *lCompData)
    01162 {
    01163         // Can do color & alpha same as dxt5, but color is pre-multiplied
    01164         //   so the result will be wrong unless corrected.
    01165         if (!DecompressDXT5(Image, CompData))
    01166                 return IL_FALSE;
    01167         CorrectPreMult();
    01168
    01169         return IL_FALSE;
    01170 }
    01171
    01172
    01173 ILboolean DecompressDXT5(ILimage *lImage, ILubyte *lCompData)
    01174 {
    01175         ILuint          x, y, z, i, j, k, Select;
    01176         ILubyte         *Temp; //, r0, g0, b0, r1, g1, b1;
    01177         Color8888       colours[4], *col;
    01178         ILuint          bitmask, Offset;
    01179         ILubyte         alphas[8], *alphamask;
    01180         ILuint          bits;
    01181
    01182         if (!lCompData)
    01183                 return IL_FALSE;
    01184
    01185         Temp = lCompData;
    01186         for (z = 0; z < lImage->Depth; z++) {
    01187                 for (y = 0; y < lImage->Height; y += 4) {
    01188                         for (x = 0; x < lImage->Width; x += 4) {
    01189                                 if (y >= lImage->Height || x >= lImage->Width)
    01190                                         break;
    01191                                 alphas[0] = Temp[0];
    01192                                 alphas[1] = Temp[1];
    01193                                 alphamask = Temp + 2;
    01194                                 Temp += 8;
    01195
    01196                                 DxtcReadColors(Temp, colours);
    01197                                 bitmask = ((ILuint*)Temp)[1];
    01198                                 UInt(&bitmask);
    01199                                 Temp += 8;
    01200
    01201                                 // Four-color block: derive the other two colors.
    01202                                 // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
    01203                                 // These 2-bit codes correspond to the 2-bit fields
    01204                                 // stored in the 64-bit block.
    01205                                 colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
    01206                                 colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
    01207                                 colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
    01208                                 //colours[2].a = 0xFF;
    01209
    01210                                 colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
    01211                                 colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
    01212                                 colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
    01213                                 //colours[3].a = 0xFF;
    01214
    01215                                 k = 0;
    01216                                 for (j = 0; j < 4; j++) {
    01217                                         for (i = 0; i < 4; i++, k++) {
    01218
    01219                                                 Select = (bitmask & (0x03 << k*2)) >> k*2;
    01220                                                 col = &colours[Select];
    01221
    01222                                                 // only put pixels out < width or height
    01223                                                 if (((x + i) < lImage->Width) && ((y + j) < lImage->Height)) {
    01224                                                         Offset = z * lImage->SizeOfPlane + (y + j) * lImage->Bps + (x + i) * lImage->Bpp;
    01225                                                         lImage->Data[Offset + 0] = col->r;
    01226                                                         lImage->Data[Offset + 1] = col->g;
    01227                                                         lImage->Data[Offset + 2] = col->b;
    01228                                                 }
    01229                                         }
    01230                                 }
    01231
    01232                                 // 8-alpha or 6-alpha block?
    01233                                 if (alphas[0] > alphas[1]) {
    01234                                         // 8-alpha block:  derive the other six alphas.
    01235                                         // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
    01236                                         alphas[2] = (6 * alphas[0] + 1 * alphas[1] + 3) / 7;    // bit code 010
    01237                                         alphas[3] = (5 * alphas[0] + 2 * alphas[1] + 3) / 7;    // bit code 011
    01238                                         alphas[4] = (4 * alphas[0] + 3 * alphas[1] + 3) / 7;    // bit code 100
    01239                                         alphas[5] = (3 * alphas[0] + 4 * alphas[1] + 3) / 7;    // bit code 101
    01240                                         alphas[6] = (2 * alphas[0] + 5 * alphas[1] + 3) / 7;    // bit code 110
    01241                                         alphas[7] = (1 * alphas[0] + 6 * alphas[1] + 3) / 7;    // bit code 111
    01242                                 }
    01243                                 else {
    01244                                         // 6-alpha block.
    01245                                         // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
    01246                                         alphas[2] = (4 * alphas[0] + 1 * alphas[1] + 2) / 5;    // Bit code 010
    01247                                         alphas[3] = (3 * alphas[0] + 2 * alphas[1] + 2) / 5;    // Bit code 011
    01248                                         alphas[4] = (2 * alphas[0] + 3 * alphas[1] + 2) / 5;    // Bit code 100
    01249                                         alphas[5] = (1 * alphas[0] + 4 * alphas[1] + 2) / 5;    // Bit code 101
    01250                                         alphas[6] = 0x00;                                                                               // Bit code 110
    01251                                         alphas[7] = 0xFF;                                                                               // Bit code 111
    01252                                 }
    01253
    01254                                 // Note: Have to separate the next two loops,
    01255                                 //      it operates on a 6-byte system.
    01256
    01257                                 // First three bytes
    01258                                 //bits = *((ILint*)alphamask);
    01259                                 bits = (alphamask[0]) | (alphamask[1] << 8) | (alphamask[2] << 16);
    01260                                 for (j = 0; j < 2; j++) {
    01261                                         for (i = 0; i < 4; i++) {
    01262                                                 // only put pixels out < width or height
    01263                                                 if (((x + i) < lImage->Width) && ((y + j) < lImage->Height)) {
    01264                                                         Offset = z * lImage->SizeOfPlane + (y + j) * lImage->Bps + (x + i) * lImage->Bpp + 3;
    01265                                                         lImage->Data[Offset] = alphas[bits & 0x07];
    01266                                                 }
    01267                                                 bits >>= 3;
    01268                                         }
    01269                                 }
    01270
    01271                                 // Last three bytes
    01272                                 //bits = *((ILint*)&alphamask[3]);
    01273                                 bits = (alphamask[3]) | (alphamask[4] << 8) | (alphamask[5] << 16);
    01274                                 for (j = 2; j < 4; j++) {
    01275                                         for (i = 0; i < 4; i++) {
    01276                                                 // only put pixels out < width or height
    01277                                                 if (((x + i) < lImage->Width) && ((y + j) < lImage->Height)) {
    01278                                                         Offset = z * lImage->SizeOfPlane + (y + j) * lImage->Bps + (x + i) * lImage->Bpp + 3;
    01279                                                         lImage->Data[Offset] = alphas[bits & 0x07];
    01280                                                 }
    01281                                                 bits >>= 3;
    01282                                         }
    01283                                 }
    01284                         }
    01285                 }
    01286         }
    01287
    01288         return IL_TRUE;
    01289 }
    01290
    01291
    01292 ILboolean Decompress3Dc()
    01293 {
    01294         int                     x, y, z, i, j, k, t1, t2;
    01295         ILubyte         *Temp, *Temp2;
    01296         ILubyte         XColours[8], YColours[8];
    01297         ILuint          bitmask, bitmask2, Offset, CurrOffset;
    01298
    01299         if (!CompData)
    01300                 return IL_FALSE;
    01301
    01302         Temp = CompData;
    01303         Offset = 0;
    01304         for (z = 0; z < Depth; z++) {
    01305                 for (y = 0; y < Height; y += 4) {
    01306                         for (x = 0; x < Width; x += 4) {
    01307                                 Temp2 = Temp + 8;
    01308
    01309                                 //Read Y palette
    01310                                 t1 = YColours[0] = Temp[0];
    01311                                 t2 = YColours[1] = Temp[1];
    01312                                 Temp += 2;
    01313                                 if (t1 > t2)
    01314                                         for (i = 2; i < 8; ++i)
    01315                                                 YColours[i] = t1 + ((t2 - t1)*(i - 1))/7;
    01316                                 else {
    01317                                         for (i = 2; i < 6; ++i)
    01318                                                 YColours[i] = t1 + ((t2 - t1)*(i - 1))/5;
    01319                                         YColours[6] = 0;
    01320                                         YColours[7] = 255;
    01321                                 }
    01322
    01323                                 // Read X palette
    01324                                 t1 = XColours[0] = Temp2[0];
    01325                                 t2 = XColours[1] = Temp2[1];
    01326                                 Temp2 += 2;
    01327                                 if (t1 > t2)
    01328                                         for (i = 2; i < 8; ++i)
    01329                                                 XColours[i] = t1 + ((t2 - t1)*(i - 1))/7;
    01330                                 else {
    01331                                         for (i = 2; i < 6; ++i)
    01332                                                 XColours[i] = t1 + ((t2 - t1)*(i - 1))/5;
    01333                                         XColours[6] = 0;
    01334                                         XColours[7] = 255;
    01335                                 }
    01336
    01337                                 //decompress pixel data
    01338                                 CurrOffset = Offset;
    01339                                 for (k = 0; k < 4; k += 2) {
    01340                                         // First three bytes
    01341                                         bitmask = ((ILuint)(Temp[0]) << 0) | ((ILuint)(Temp[1]) << 8) | ((ILuint)(Temp[2]) << 16);
    01342                                         bitmask2 = ((ILuint)(Temp2[0]) << 0) | ((ILuint)(Temp2[1]) << 8) | ((ILuint)(Temp2[2]) << 16);
    01343                                         for (j = 0; j < 2; j++) {
    01344                                                 // only put pixels out < height
    01345                                                 if ((y + k + j) < Height) {
    01346                                                         for (i = 0; i < 4; i++) {
    01347                                                                 // only put pixels out < width
    01348                                                                 if (((x + i) < Width)) {
    01349                                                                         ILint t, tx, ty;
    01350
    01351                                                                         t1 = CurrOffset + (x + i)*3;
    01352                                                                         Image->Data[t1 + 1] = ty = YColours[bitmask & 0x07];
    01353                                                                         Image->Data[t1 + 0] = tx = XColours[bitmask2 & 0x07];
    01354
    01355                                                                         //calculate b (z) component ((r/255)^2 + (g/255)^2 + (b/255)^2 = 1
    01356                                                                         t = 127*128 - (tx - 127)*(tx - 128) - (ty - 127)*(ty - 128);
    01357                                                                         if (t > 0)
    01358                                                                                 Image->Data[t1 + 2] = (ILubyte)(iSqrt(t) + 128);
    01359                                                                         else
    01360                                                                                 Image->Data[t1 + 2] = 0x7F;
    01361                                                                 }
    01362                                                                 bitmask >>= 3;
    01363                                                                 bitmask2 >>= 3;
    01364                                                         }
    01365                                                         CurrOffset += Image->Bps;
    01366                                                 }
    01367                                         }
    01368                                         Temp += 3;
    01369                                         Temp2 += 3;
    01370                                 }
    01371
    01372                                 //skip bytes that were read via Temp2
    01373                                 Temp += 8;
    01374                         }
    01375                         Offset += Image->Bps*4;
    01376                 }
    01377         }
    01378
    01379         return IL_TRUE;
    01380 }
    01381
    01382
    01383 ILboolean DecompressAti1n()
    01384 {
    01385         int                     x, y, z, i, j, k, t1, t2;
    01386         ILubyte         *Temp;
    01387         ILubyte         Colours[8];
    01388         ILuint          bitmask, Offset, CurrOffset;
    01389
    01390         if (!CompData)
    01391                 return IL_FALSE;
    01392
    01393         Temp = CompData;
    01394         Offset = 0;
    01395         for (z = 0; z < Depth; z++) {
    01396                 for (y = 0; y < Height; y += 4) {
    01397                         for (x = 0; x < Width; x += 4) {
    01398                                 //Read palette
    01399                                 t1 = Colours[0] = Temp[0];
    01400                                 t2 = Colours[1] = Temp[1];
    01401                                 Temp += 2;
    01402                                 if (t1 > t2)
    01403                                         for (i = 2; i < 8; ++i)
    01404                                                 Colours[i] = t1 + ((t2 - t1)*(i - 1))/7;
    01405                                 else {
    01406                                         for (i = 2; i < 6; ++i)
    01407                                                 Colours[i] = t1 + ((t2 - t1)*(i - 1))/5;
    01408                                         Colours[6] = 0;
    01409                                         Colours[7] = 255;
    01410                                 }
    01411
    01412                                 //decompress pixel data
    01413                                 CurrOffset = Offset;
    01414                                 for (k = 0; k < 4; k += 2) {
    01415                                         // First three bytes
    01416                                         bitmask = ((ILuint)(Temp[0]) << 0) | ((ILuint)(Temp[1]) << 8) | ((ILuint)(Temp[2]) << 16);
    01417                                         for (j = 0; j < 2; j++) {
    01418                                                 // only put pixels out < height
    01419                                                 if ((y + k + j) < Height) {
    01420                                                         for (i = 0; i < 4; i++) {
    01421                                                                 // only put pixels out < width
    01422                                                                 if (((x + i) < Width)) {
    01423                                                                         t1 = CurrOffset + (x + i);
    01424                                                                         Image->Data[t1] = Colours[bitmask & 0x07];
    01425                                                                 }
    01426                                                                 bitmask >>= 3;
    01427                                                         }
    01428                                                         CurrOffset += Image->Bps;
    01429                                                 }
    01430                                         }
    01431                                         Temp += 3;
    01432                                 }
    01433                         }
    01434                         Offset += Image->Bps*4;
    01435                 }
    01436         }
    01437
    01438         return IL_TRUE;
    01439 }
    01440
    01441
    01442 //This is nearly exactly the same as DecompressDXT5...
    01443 //I have to clean up this file (put common code in
    01444 //helper functions etc)
    01445 ILboolean DecompressRXGB()
    01446 {
    01447         int                     x, y, z, i, j, k, Select;
    01448         ILubyte         *Temp;
    01449         Color565        *color_0, *color_1;
    01450         Color8888       colours[4], *col;
    01451         ILuint          bitmask, Offset;
    01452         ILubyte         alphas[8], *alphamask;
    01453         ILuint          bits;
    01454
    01455         if (!CompData)
    01456                 return IL_FALSE;
    01457
    01458         Temp = CompData;
    01459         for (z = 0; z < Depth; z++) {
    01460                 for (y = 0; y < Height; y += 4) {
    01461                         for (x = 0; x < Width; x += 4) {
    01462                                 if (y >= Height || x >= Width)
    01463                                         break;
    01464                                 alphas[0] = Temp[0];
    01465                                 alphas[1] = Temp[1];
    01466                                 alphamask = Temp + 2;
    01467                                 Temp += 8;
    01468                                 color_0 = ((Color565*)Temp);
    01469                                 color_1 = ((Color565*)(Temp+2));
    01470                                 bitmask = ((ILuint*)Temp)[1];
    01471                                 Temp += 8;
    01472
    01473                                 colours[0].r = color_0->nRed << 3;
    01474                                 colours[0].g = color_0->nGreen << 2;
    01475                                 colours[0].b = color_0->nBlue << 3;
    01476                                 colours[0].a = 0xFF;
    01477
    01478                                 colours[1].r = color_1->nRed << 3;
    01479                                 colours[1].g = color_1->nGreen << 2;
    01480                                 colours[1].b = color_1->nBlue << 3;
    01481                                 colours[1].a = 0xFF;
    01482
    01483                                 // Four-color block: derive the other two colors.
    01484                                 // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
    01485                                 // These 2-bit codes correspond to the 2-bit fields
    01486                                 // stored in the 64-bit block.
    01487                                 colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
    01488                                 colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
    01489                                 colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
    01490                                 colours[2].a = 0xFF;
    01491
    01492                                 colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
    01493                                 colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
    01494                                 colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
    01495                                 colours[3].a = 0xFF;
    01496
    01497                                 k = 0;
    01498                                 for (j = 0; j < 4; j++) {
    01499                                         for (i = 0; i < 4; i++, k++) {
    01500
    01501                                                 Select = (bitmask & (0x03 << k*2)) >> k*2;
    01502                                                 col = &colours[Select];
    01503
    01504                                                 // only put pixels out < width or height
    01505                                                 if (((x + i) < Width) && ((y + j) < Height)) {
    01506                                                         Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp;
    01507                                                         Image->Data[Offset + 0] = col->r;
    01508                                                         Image->Data[Offset + 1] = col->g;
    01509                                                         Image->Data[Offset + 2] = col->b;
    01510                                                 }
    01511                                         }
    01512                                 }
    01513
    01514                                 // 8-alpha or 6-alpha block?
    01515                                 if (alphas[0] > alphas[1]) {
    01516                                         // 8-alpha block:  derive the other six alphas.
    01517                                         // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
    01518                                         alphas[2] = (6 * alphas[0] + 1 * alphas[1] + 3) / 7;    // bit code 010
    01519                                         alphas[3] = (5 * alphas[0] + 2 * alphas[1] + 3) / 7;    // bit code 011
    01520                                         alphas[4] = (4 * alphas[0] + 3 * alphas[1] + 3) / 7;    // bit code 100
    01521                                         alphas[5] = (3 * alphas[0] + 4 * alphas[1] + 3) / 7;    // bit code 101
    01522                                         alphas[6] = (2 * alphas[0] + 5 * alphas[1] + 3) / 7;    // bit code 110
    01523                                         alphas[7] = (1 * alphas[0] + 6 * alphas[1] + 3) / 7;    // bit code 111
    01524                                 }
    01525                                 else {
    01526                                         // 6-alpha block.
    01527                                         // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
    01528                                         alphas[2] = (4 * alphas[0] + 1 * alphas[1] + 2) / 5;    // Bit code 010
    01529                                         alphas[3] = (3 * alphas[0] + 2 * alphas[1] + 2) / 5;    // Bit code 011
    01530                                         alphas[4] = (2 * alphas[0] + 3 * alphas[1] + 2) / 5;    // Bit code 100
    01531                                         alphas[5] = (1 * alphas[0] + 4 * alphas[1] + 2) / 5;    // Bit code 101
    01532                                         alphas[6] = 0x00;                                                                               // Bit code 110
    01533                                         alphas[7] = 0xFF;                                                                               // Bit code 111
    01534                                 }
    01535
    01536                                 // Note: Have to separate the next two loops,
    01537                                 //      it operates on a 6-byte system.
    01538                                 // First three bytes
    01539                                 bits = *((ILint*)alphamask);
    01540                                 for (j = 0; j < 2; j++) {
    01541                                         for (i = 0; i < 4; i++) {
    01542                                                 // only put pixels out < width or height
    01543                                                 if (((x + i) < Width) && ((y + j) < Height)) {
    01544                                                         Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp + 0;
    01545                                                         Image->Data[Offset] = alphas[bits & 0x07];
    01546                                                 }
    01547                                                 bits >>= 3;
    01548                                         }
    01549                                 }
    01550
    01551                                 // Last three bytes
    01552                                 bits = *((ILint*)&alphamask[3]);
    01553                                 for (j = 2; j < 4; j++) {
    01554                                         for (i = 0; i < 4; i++) {
    01555                                                 // only put pixels out < width or height
    01556                                                 if (((x + i) < Width) && ((y + j) < Height)) {
    01557                                                         Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp + 0;
    01558                                                         Image->Data[Offset] = alphas[bits & 0x07];
    01559                                                 }
    01560                                                 bits >>= 3;
    01561                                         }
    01562                                 }
    01563                         }
    01564                 }
    01565         }
    01566
    01567         return IL_TRUE;
    01568 }
    01569
    01570
    01571 //Taken from OpenEXR
    01572 unsigned int
    01573 halfToFloat (unsigned short y)
    01574 {
    01575         int s = (y >> 15) & 0x00000001;
    01576         int e = (y >> 10) & 0x0000001f;
    01577         int m =  y                & 0x000003ff;
    01578
    01579         if (e == 0)
    01580         {
    01581                 if (m == 0)
    01582                 {
    01583                         //
    01584                         // Plus or minus zero
    01585                         //
    01586                         return s << 31;
    01587                 }
    01588                 else
    01589                 {
    01590                         //
    01591                         // Denormalized number -- renormalize it
    01592                         //
    01593                         while (!(m & 0x00000400))
    01594                         {
    01595                                 m <<= 1;
    01596                                 e -=  1;
    01597                         }
    01598
    01599                         e += 1;
    01600                         m &= ~0x00000400;
    01601                 }
    01602         }
    01603         else if (e == 31)
    01604         {
    01605                 if (m == 0)
    01606                 {
    01607                         //
    01608                         // Positive or negative infinity
    01609                         //
    01610                         return (s << 31) | 0x7f800000;
    01611                 }
    01612                 else
    01613                 {
    01614                         //
    01615                         // Nan -- preserve sign and significand bits
    01616                         //
    01617                         return (s << 31) | 0x7f800000 | (m << 13);
    01618                 }
    01619         }
    01620
    01621         //
    01622         // Normalized number
    01623         //
    01624         e = e + (127 - 15);
    01625         m = m << 13;
    01626
    01627         //
    01628         // Assemble s, e and m.
    01629         //
    01630         return (s << 31) | (e << 23) | m;
    01631 }
    01632
    01633
    01634 ILboolean iConvFloat16ToFloat32(ILuint* dest, ILushort* src, ILuint size)
    01635 {
    01636         ILuint i;
    01637         for (i = 0; i < size; ++i, ++dest, ++src) {
    01638                 //float: 1 sign bit, 8 exponent bits, 23 mantissa bits
    01639                 //half: 1 sign bit, 5 exponent bits, 10 mantissa bits
    01640                 *dest = halfToFloat(*src);
    01641         }
    01642
    01643         return IL_TRUE;
    01644 }
    01645
    01646
    01647 ILboolean DecompressFloat(ILuint lCompFormat)
    01648 {
    01649         switch (lCompFormat)
    01650         {
    01651                 case PF_R32F:
    01652                 case PF_G32R32F:
    01653                 case PF_A32B32G32R32F:
    01654                         memcpy(Image->Data, CompData, Image->SizeOfData);
    01655                         return IL_TRUE;
    01656                 case PF_R16F:
    01657                 case PF_G16R16F:
    01658                 case PF_A16B16G16R16F:
    01659                         return iConvFloat16ToFloat32((ILuint*)Image->Data, (ILushort*)CompData,
    01660                                 Image->Width * Image->Height * Image->Depth * Image->Bpp);
    01661                 default:
    01662                         return IL_FALSE;
    01663         }
    01664 }
    01665
    01666
    01667 void CorrectPreMult()
    01668 {
    01669         ILuint i;
    01670
    01671         for (i = 0; i < Image->SizeOfData; i += 4) {
    01672                 if (Image->Data[i+3] != 0) {  // Cannot divide by 0.
    01673                         Image->Data[i]   = (ILubyte)(((ILuint)Image->Data[i]   << 8) / Image->Data[i+3]);
    01674                         Image->Data[i+1] = (ILubyte)(((ILuint)Image->Data[i+1] << 8) / Image->Data[i+3]);
    01675                         Image->Data[i+2] = (ILubyte)(((ILuint)Image->Data[i+2] << 8) / Image->Data[i+3]);
    01676                 }
    01677         }
    01678
    01679         return;
    01680 }
    01681
    01682
    01683 ILboolean DecompressARGB() {
    01684         ILuint ReadI = 0, TempBpp, i;
    01685         ILuint RedL, RedR;
    01686         ILuint GreenL, GreenR;
    01687         ILuint BlueL, BlueR;
    01688         ILuint AlphaL, AlphaR;
    01689         ILubyte *Temp;
    01690
    01691         if (!CompData)
    01692                 return IL_FALSE;
    01693
    01694         if(CompFormat == PF_LUMINANCE && Head.RGBBitCount == 16 && Head.RBitMask == 0xFFFF) { //HACK
    01695                 memcpy(Image->Data, CompData, Image->SizeOfData);
    01696                 return IL_TRUE;
    01697         }
    01698
    01699         GetBitsFromMask(Head.RBitMask, &RedL, &RedR);
    01700         GetBitsFromMask(Head.GBitMask, &GreenL, &GreenR);
    01701         GetBitsFromMask(Head.BBitMask, &BlueL, &BlueR);
    01702         GetBitsFromMask(Head.RGBAlphaBitMask, &AlphaL, &AlphaR);
    01703         Temp = CompData;
    01704         TempBpp = Head.RGBBitCount / 8;
    01705
    01706         for (i = 0; i < Image->SizeOfData; i += Image->Bpp) {
    01707
    01708                 //@TODO: This is SLOOOW...
    01709                 //but the old version crashed in release build under
    01710                 //winxp (and xp is right to stop this code - I always
    01711                 //wondered that it worked the old way at all)
    01712                 if (Image->SizeOfData - i < 4) { //less than 4 byte to write?
    01713                         if (TempBpp == 3) { //this branch is extra-SLOOOW
    01714                                 ReadI =
    01715                                         *Temp
    01716                                         | ((*(Temp + 1)) << 8)
    01717                                         | ((*(Temp + 2)) << 16);
    01718                         }
    01719                         else if (TempBpp == 1)
    01720                                 ReadI = *((ILubyte*)Temp);
    01721                         else if (TempBpp == 2)
    01722                                 ReadI = Temp[0] | (Temp[1] << 8);
    01723                 }
    01724                 else
    01725                         ReadI = Temp[0] | (Temp[1] << 8) | (Temp[2] << 16) | (Temp[3] << 24);
    01726                 Temp += TempBpp;
    01727
    01728                 Image->Data[i] = ((ReadI & Head.RBitMask) >> RedR) << RedL;
    01729
    01730                 if(Image->Bpp >= 3) {
    01731                         Image->Data[i+1] = ((ReadI & Head.GBitMask) >> GreenR) << GreenL;
    01732                         Image->Data[i+2] = ((ReadI & Head.BBitMask) >> BlueR) << BlueL;
    01733
    01734                         if (Image->Bpp == 4) {
    01735                                 Image->Data[i+3] = ((ReadI & Head.RGBAlphaBitMask) >> AlphaR) << AlphaL;
    01736                                 if (AlphaL >= 7) {
    01737                                         Image->Data[i+3] = Image->Data[i+3] ? 0xFF : 0x00;
    01738                                 }
    01739                                 else if (AlphaL >= 4) {
    01740                                         Image->Data[i+3] = Image->Data[i+3] | (Image->Data[i+3] >> 4);
    01741                                 }
    01742                         }
    01743                 }
    01744                 else if (Image->Bpp == 2) {
    01745                         Image->Data[i+1] = ((ReadI & Head.RGBAlphaBitMask) >> AlphaR) << AlphaL;
    01746                         if (AlphaL >= 7) {
    01747                                 Image->Data[i+1] = Image->Data[i+1] ? 0xFF : 0x00;
    01748                         }
    01749                         else if (AlphaL >= 4) {
    01750                                 Image->Data[i+1] = Image->Data[i+1] | (Image->Data[i+3] >> 4);
    01751                         }
    01752                 }
    01753         }
    01754
    01755         return IL_TRUE;
    01756 }
    01757
    01758
    01759 // @TODO:  Look at using the BSF/BSR operands for inline ASM here.
    01760 void GetBitsFromMask(ILuint Mask, ILuint *ShiftLeft, ILuint *ShiftRight)
    01761 {
    01762         ILuint Temp, i;
    01763
    01764         if (Mask == 0) {
    01765                 *ShiftLeft = *ShiftRight = 0;
    01766                 return;
    01767         }
    01768
    01769         Temp = Mask;
    01770         for (i = 0; i < 32; i++, Temp >>= 1) {
    01771                 if (Temp & 1)
    01772                         break;
    01773         }
    01774         *ShiftRight = i;
    01775
    01776         // Temp is preserved, so use it again:
    01777         for (i = 0; i < 8; i++, Temp >>= 1) {
    01778                 if (!(Temp & 1))
    01779                         break;
    01780         }
    01781         *ShiftLeft = 8 - i;
    01782
    01783         return;
    01784 }
    01785
    01786
    01787 //
    01788 //
    01789 // DXT extension code
    01790 //
    01791 //
    01792 ILubyte* ILAPIENTRY ilGetDxtcData()
    01793 {
    01794         if (iCurImage == NULL) {
    01795                 ilSetError(IL_INTERNAL_ERROR);
    01796                 return NULL;
    01797         }
    01798         return iCurImage->DxtcData;
    01799 }
    01800
    01801 void ilFreeSurfaceDxtcData()
    01802 {
    01803         if (iCurImage != NULL && iCurImage->DxtcData != NULL) {
    01804                 ifree(iCurImage->DxtcData);
    01805                 iCurImage->DxtcData = NULL;
    01806                 iCurImage->DxtcSize = 0;
    01807                 iCurImage->DxtcFormat = IL_DXT_NO_COMP;
    01808         }
    01809 }
    01810
    01811 void ilFreeImageDxtcData()
    01812 {
    01813         ILint i, j;
    01814         ILuint ImgID = ilGetInteger(IL_CUR_IMAGE);
    01815         ILint ImgCount = ilGetInteger(IL_NUM_IMAGES);
    01816         ILint MipCount;
    01817
    01818         for(i = 0; i <= ImgCount; ++i) {
    01819                 ilBindImage(ImgID);
    01820                 ilActiveImage(i);
    01821
    01822                 MipCount = ilGetInteger(IL_NUM_MIPMAPS);
    01823                 for(j = 0; j <= MipCount; ++j) {
    01824                         ilBindImage(ImgID);
    01825                         ilActiveImage(i);
    01826                         ilActiveMipmap(j);
    01827
    01828                         ilFreeSurfaceDxtcData();
    01829                 }
    01830         }
    01831 }
    01832
    01833 /*
    01834  * This assumes DxtcData, DxtcFormat, width, height, and depth are valid
    01835  */
    01836 ILAPI ILboolean ILAPIENTRY ilDxtcDataToSurface()
    01837 {
    01838         if (iCurImage == NULL || iCurImage->DxtcData == NULL) {
    01839                 ilSetError(IL_INVALID_PARAM);
    01840                 return IL_FALSE;
    01841         }
    01842
    01843         if (!(iCurImage->DxtcFormat == IL_DXT1 || iCurImage->DxtcFormat == IL_DXT3
    01844                 || iCurImage->DxtcFormat == IL_DXT5)) {
    01845                 ilSetError(IL_INVALID_PARAM); //TODO
    01846                 return IL_FALSE;
    01847         }
    01848
    01849         //@TODO: is this right for all dxt formats? works for
    01850         //  DXT1, 3, 5
    01851         iCurImage->Bpp = 4;
    01852         iCurImage->Bpc = 1;
    01853         iCurImage->Bps = iCurImage->Width*iCurImage->Bpp*iCurImage->Bpc;
    01854         iCurImage->SizeOfPlane = iCurImage->Height*iCurImage->Bps;
    01855         iCurImage->Format = IL_RGBA;
    01856         iCurImage->Type = IL_UNSIGNED_BYTE;
    01857
    01858         if (iCurImage->SizeOfData != iCurImage->SizeOfPlane*iCurImage->Depth) {
    01859                 iCurImage->SizeOfData = iCurImage->Depth*iCurImage->SizeOfPlane;
    01860                 if (iCurImage->Data != NULL)
    01861                         ifree(iCurImage->Data);
    01862                 iCurImage->Data = NULL;
    01863         }
    01864
    01865         if (iCurImage->Data == NULL) {
    01866                 iCurImage->Data = ialloc(iCurImage->SizeOfData);
    01867         }
    01868
    01869         Image = iCurImage;
    01870         Width = iCurImage->Width;
    01871         Height = iCurImage->Height;
    01872         Depth = iCurImage->Depth;
    01873         switch(iCurImage->DxtcFormat)
    01874         {
    01875                 case IL_DXT1: CompFormat = PF_DXT1; break;
    01876                 case IL_DXT3: CompFormat = PF_DXT3; break;
    01877                 case IL_DXT5: CompFormat = PF_DXT5; break;
    01878         }
    01879         CompData = iCurImage->DxtcData;
    01880         Decompress(); //globals suck...fix this
    01881
    01882         //@TODO: origin should be set in Decompress()...
    01883         iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
    01884         return ilFixCur();
    01885 }
    01886
    01887
    01888 ILAPI ILboolean ILAPIENTRY ilDxtcDataToImage()
    01889 {
    01890         ILint i, j;
    01891         ILuint ImgID = ilGetInteger(IL_CUR_IMAGE);
    01892         ILint ImgCount = ilGetInteger(IL_NUM_IMAGES);
    01893         ILint MipCount;
    01894         ILboolean ret = IL_TRUE;
    01895
    01896         for(i = 0; i <= ImgCount; ++i) {
    01897                 ilBindImage(ImgID);
    01898                 ilActiveImage(i);
    01899
    01900                 MipCount = ilGetInteger(IL_NUM_MIPMAPS);
    01901                 for(j = 0; j <= MipCount; ++j) {
    01902                         ilBindImage(ImgID);
    01903                         ilActiveImage(i);
    01904                         ilActiveMipmap(j);
    01905
    01906                         if (!ilDxtcDataToSurface())
    01907                                 ret = IL_FALSE;
    01908                 }
    01909         }
    01910     ilBindImage(ImgID);
    01911
    01912         return ret;
    01913 }
    01914
    01915
    01916 ILAPI ILboolean ILAPIENTRY ilSurfaceToDxtcData(ILenum Format)
    01917 {
    01918         ILuint Size;
    01919         void* Data;
    01920         ilFreeSurfaceDxtcData();
    01921
    01922         Size = ilGetDXTCData(NULL, 0, Format);
    01923         if (Size == 0) {
    01924                 return IL_FALSE;
    01925         }
    01926
    01927         Data = ialloc(Size);
    01928
    01929         if (Data == NULL)
    01930                 return IL_FALSE;
    01931
    01932         ilGetDXTCData(Data, Size, Format);
    01933
    01934         //These have to be after the call to ilGetDXTCData()
    01935         iCurImage->DxtcData = Data;
    01936         iCurImage->DxtcFormat = Format;
    01937         iCurImage->DxtcSize = Size;
    01938
    01939         return IL_TRUE;
    01940 }
    01941
    01942
    01943 ILAPI ILboolean ILAPIENTRY ilImageToDxtcData(ILenum Format)
    01944 {
    01945         ILint i, j;
    01946         ILuint ImgID = ilGetInteger(IL_CUR_IMAGE);
    01947         ILint ImgCount = ilGetInteger(IL_NUM_IMAGES);
    01948         ILint MipCount;
    01949         ILboolean ret = IL_TRUE;
    01950
    01951         for (i = 0; i <= ImgCount; ++i) {
    01952                 ilBindImage(ImgID);
    01953                 ilActiveImage(i);
    01954
    01955                 MipCount = ilGetInteger(IL_NUM_MIPMAPS);
    01956                 for(j = 0; j <= MipCount; ++j) {
    01957                         ilBindImage(ImgID);
    01958                         ilActiveImage(i);
    01959                         ilActiveMipmap(j);
    01960
    01961                         if (!ilSurfaceToDxtcData(Format))
    01962                                 ret = IL_FALSE;
    01963                 }
    01964         }
    01965
    01966         return ret;
    01967 }
    01968
    01969
    01970 //works like ilTexImage(), ie. destroys mipmaps etc (which sucks, but
    01971 //is consistent. There should be a ilTexSurface() and ilTexSurfaceDxtc()
    01972 //functions as well, but for now this is sufficient)
    01973 ILAPI ILboolean ILAPIENTRY ilTexImageDxtc(ILint w, ILint h, ILint d, ILenum DxtFormat, const ILubyte* data)
    01974 {
    01975         ILimage* Image = iCurImage;
    01976
    01977         ILint xBlocks, yBlocks, BlockSize, LineSize, DataSize;
    01978
    01979
    01980         //The next few lines are copied from ilTexImage() and ilInitImage() -
    01981         //should be factored in more reusable functions...
    01982         if (Image == NULL) {
    01983                 ilSetError(IL_ILLEGAL_OPERATION);
    01984                 return IL_FALSE;
    01985         }
    01986
    01988
    01989         // Not sure if we should be getting rid of the palette...
    01990         if (Image->Pal.Palette && Image->Pal.PalSize && Image->Pal.PalType != IL_PAL_NONE) {
    01991                 ifree(Image->Pal.Palette);
    01992         }
    01993
    01994         // These are set NULL later by the memset call.
    01995         ilCloseImage(Image->Mipmaps);
    01996         ilCloseImage(Image->Next);
    01997         ilCloseImage(Image->Faces);
    01998         ilCloseImage(Image->Layers);
    01999
    02000         if (Image->AnimList) ifree(Image->AnimList);
    02001         if (Image->Profile)  ifree(Image->Profile);
    02002         if (Image->DxtcData) ifree(Image->DxtcData);
    02003         if (Image->Data)         ifree(Image->Data);
    02004
    02005
    02007
    02008         memset(Image, 0, sizeof(ILimage));
    02009         Image->Width       = w;
    02010         Image->Height      = h;
    02011         Image->Depth       = d;
    02012
    02013         //TODO: What about origin with dxtc data?
    02014         Image->Origin      = IL_ORIGIN_LOWER_LEFT;
    02015         Image->Pal.PalType = IL_PAL_NONE;
    02016
    02017     // Allocate DXT data buffer
    02018         xBlocks = (w + 3)/4;
    02019         yBlocks = (h + 3)/4;
    02020         if (DxtFormat == IL_DXT1)
    02021                 BlockSize = 8;
    02022         else
    02023                 BlockSize = 16;
    02024
    02025         LineSize = xBlocks * BlockSize;
    02026
    02027         DataSize = yBlocks * LineSize * d;
    02028
    02029         Image->DxtcFormat  = DxtFormat;
    02030         Image->DxtcSize = DataSize;
    02031         Image->DxtcData    = ialloc(DataSize);
    02032
    02033         if (Image->DxtcData == NULL) {
    02034                 return IL_FALSE;
    02035         }
    02036
    02037         if (data != NULL)
    02038                 memcpy(Image->DxtcData, data, DataSize);
    02039
    02040         return IL_TRUE;
    02041 }
    02042
    02043
    02044 /* ------------------------------------------------------------------- */
    02045
    02046 void iFlipColorBlock(ILubyte *data)
    02047 {
    02048     ILubyte tmp;
    02049
    02050     tmp = data[4];
    02051     data[4] = data[7];
    02052     data[7] = tmp;
    02053
    02054     tmp = data[5];
    02055     data[5] = data[6];
    02056     data[6] = tmp;
    02057 }
    02058
    02059 void iFlipSimpleAlphaBlock(ILushort *data)
    02060 {
    02061         ILushort tmp;
    02062
    02063         tmp = data[0];
    02064         data[0] = data[3];
    02065         data[3] = tmp;
    02066
    02067         tmp = data[1];
    02068         data[1] = data[2];
    02069         data[2] = tmp;
    02070 }
    02071
    02072 void iComplexAlphaHelper(ILubyte* Data)
    02073 {
    02074         ILushort tmp[2];
    02075
    02076         //one 4 pixel line is 12 bit, copy each line into
    02077         //a ushort, swap them and copy back
    02078         tmp[0] = (Data[0] | (Data[1] << 8)) & 0xfff;
    02079         tmp[1] = ((Data[1] >> 4) | (Data[2] << 4)) & 0xfff;
    02080
    02081         Data[0] = (ILubyte)tmp[1];
    02082         Data[1] = (tmp[1] >> 8) | (tmp[0] << 4);
    02083         Data[2] = tmp[0] >> 4;
    02084 }
    02085
    02086 void iFlipComplexAlphaBlock(ILubyte *Data)
    02087 {
    02088         ILubyte tmp[3];
    02089         Data += 2; //Skip 'palette'
    02090
    02091         //swap upper two rows with lower two rows
    02092         memcpy(tmp, Data, 3);
    02093         memcpy(Data, Data + 3, 3);
    02094         memcpy(Data + 3, tmp, 3);
    02095
    02096         //swap 1st with 2nd row, 3rd with 4th
    02097         iComplexAlphaHelper(Data);
    02098         iComplexAlphaHelper(Data + 3);
    02099 }
    02100
    02101 void iFlipDxt1(ILubyte* data, ILuint count)
    02102 {
    02103         ILuint i;
    02104
    02105         for (i = 0; i < count; ++i) {
    02106                 iFlipColorBlock(data);
    02107                 data += 8; //advance to next block
    02108         }
    02109 }
    02110
    02111 void iFlipDxt3(ILubyte* data, ILuint count)
    02112 {
    02113         ILuint i;
    02114         for (i = 0; i < count; ++i) {
    02115                 iFlipSimpleAlphaBlock((ILushort*)data);
    02116                 iFlipColorBlock(data + 8);
    02117                 data += 16; //advance to next block
    02118         }
    02119 }
    02120
    02121 void iFlipDxt5(ILubyte* data, ILuint count)
    02122 {
    02123         ILuint i;
    02124         for (i = 0; i < count; ++i) {
    02125                 iFlipComplexAlphaBlock(data);
    02126                 iFlipColorBlock(data + 8);
    02127                 data += 16; //advance to next block
    02128         }
    02129 }
    02130
    02131 void iFlip3dc(ILubyte* data, ILuint count)
    02132 {
    02133         ILuint i;
    02134         for (i = 0; i < count; ++i) {
    02135                 iFlipComplexAlphaBlock(data);
    02136                 iFlipComplexAlphaBlock(data + 8);
    02137                 data += 16; //advance to next block
    02138         }
    02139 }
    02140
    02141
    02142 ILAPI void ILAPIENTRY ilFlipSurfaceDxtcData()
    02143 {
    02144         ILuint y, z;
    02145         ILuint BlockSize, LineSize;
    02146         ILubyte *Temp, *Runner, *Top, *Bottom;
    02147         ILuint numXBlocks, numYBlocks;
    02148         void (*FlipBlocks)(ILubyte* data, ILuint count);
    02149
    02150         if (iCurImage == NULL || iCurImage->DxtcData == NULL) {
    02151                 ilSetError(IL_INVALID_PARAM);
    02152                 return;
    02153         }
    02154
    02155         numXBlocks = (iCurImage->Width + 3)/4;
    02156         numYBlocks = (iCurImage->Height + 3)/4;
    02157
    02158         switch (iCurImage->DxtcFormat)
    02159         {
    02160                 case IL_DXT1:
    02161                         BlockSize = 8;
    02162                         FlipBlocks = iFlipDxt1;
    02163                         break;
    02164                 case IL_DXT2:
    02165                 case IL_DXT3:
    02166                         BlockSize = 16;
    02167                         FlipBlocks = iFlipDxt3;
    02168                         break;
    02169                 case IL_DXT4:
    02170                 case IL_DXT5:
    02171                 case IL_RXGB:
    02172                         BlockSize = 16;
    02173                         FlipBlocks = iFlipDxt5;
    02174                         break;
    02175                 case IL_3DC:
    02176                         BlockSize = 16;
    02177                         FlipBlocks = iFlip3dc;
    02178                         break;
    02179                 default:
    02180                         ilSetError(IL_INVALID_PARAM);
    02181                         return;
    02182         }
    02183
    02184         LineSize = numXBlocks * BlockSize;
    02185         Temp = ialloc(LineSize);
    02186
    02187         if (Temp == NULL)
    02188             return;
    02189
    02190         Runner = iCurImage->DxtcData;
    02191         for (z = 0; z < iCurImage->Depth; ++z) {
    02192                 Top = Runner;
    02193                 Bottom = Runner + (numYBlocks - 1)*LineSize;
    02194
    02195                 for (y = 0; y < numYBlocks/2; ++y) {
    02196                         //swap block row
    02197                         memcpy(Temp, Top, LineSize);
    02198                         memcpy(Top, Bottom, LineSize);
    02199                         memcpy(Bottom, Temp, LineSize);
    02200
    02201
    02202                         //swap blocks
    02203                         FlipBlocks(Top, numXBlocks);
    02204                         FlipBlocks(Bottom, numXBlocks);
    02205
    02206                         Top += LineSize;
    02207                         Bottom -= LineSize;
    02208                 }
    02209
    02210                 //middle line
    02211                 if (numYBlocks % 2 != 0)
    02212                         FlipBlocks(Top, numXBlocks);
    02213
    02214                 Runner += LineSize * numYBlocks;
    02215         }
    02216
    02217         ifree(Temp);
    02218 }
    02219
    02220 /**********************************************************************/
    02221
    02222 void iInvertDxt3Alpha(ILubyte *data)
    02223 {
    02224         ILint i;
    02225
    02226         for (i = 0; i < 8; ++i) {
    02227                 /*
    02228                 ILubyte b, t1, t2;
    02229                 b = data[i];
    02230
    02231                 t1 = b & 0xf;
    02232                 t1 = 15 - t1;
    02233                 t2 = b >> 4;
    02234                 t2 = 15 - t2;
    02235
    02236                 data[i] = (t2 << 4) | t1;
    02237                 */
    02238                 //simpler:
    02239                 data[i] = ~data[i];
    02240         }
    02241 }
    02242
    02243 void iInvertDxt5Alpha(ILubyte *data)
    02244 {
    02245         ILubyte a0, a1;
    02246         ILint i, j;
    02247         const ILubyte map1[] = { 1, 0, 7, 6, 5, 4, 3, 2 };
    02248         const ILubyte map2[] = { 1, 0, 5, 4, 3, 2, 7, 6 };
    02249
    02250
    02251         a0 = data[0];
    02252         a1 = data[1];
    02253
    02254         //a0 > a1 <=> 255 - a0 < 255 - a1. Because of this,
    02255         //a1 and a2 have to be swapped, and the indices
    02256         //have to be changed as well.
    02257
    02258         //invert and swap alpha
    02259         data[0] = 255 - a1;
    02260         data[1] = 255 - a0;
    02261         data += 2;
    02262
    02263         //fix indices
    02264         for (i = 0; i < 6; i += 3) {
    02265                 ILuint in = data[i] | (data[i+1] << 8) | (data[i+2] << 16);
    02266                 ILuint out = 0;
    02267
    02268                 for (j = 0; j < 24; j += 3) {
    02269                         ILubyte b = (in >> j) & 0x7;
    02270
    02271                         if (a0 > a1)
    02272                                 b = map1[b];
    02273                         else
    02274                                 b = map2[b];
    02275
    02276                         out |= b << j;
    02277                 }
    02278
    02279                 data[i] = out;
    02280                 data[i+1] = out >> 8;
    02281                 data[i+2] = out >> 16;
    02282         }
    02283 }
    02284
    02285
    02286 ILAPI ILboolean ILAPIENTRY ilInvertSurfaceDxtcDataAlpha()
    02287 {
    02288         ILint i;
    02289         ILuint BlockSize;
    02290         ILubyte *Runner;
    02291         ILint numXBlocks, numYBlocks, numBlocks;
    02292         void (*InvertAlpha)(ILubyte* data);
    02293
    02294         if (iCurImage == NULL || iCurImage->DxtcData == NULL) {
    02295                 ilSetError(IL_INVALID_PARAM);
    02296                 return IL_FALSE;
    02297         }
    02298
    02299         numXBlocks = (iCurImage->Width + 3)/4;
    02300         numYBlocks = (iCurImage->Height + 3)/4;
    02301         numBlocks = numXBlocks*numYBlocks*iCurImage->Depth;
    02302         BlockSize = 16;
    02303
    02304         switch (iCurImage->DxtcFormat)
    02305         {
    02306                 case IL_DXT3:
    02307                         InvertAlpha = iInvertDxt3Alpha;
    02308                         break;
    02309                 case IL_DXT5:
    02310                         InvertAlpha = iInvertDxt5Alpha;
    02311                         break;
    02312                 default:
    02313                         //DXT2/4 are not supported yet because nobody
    02314                         //uses them anyway and I would have to change
    02315                         //the color blocks as well...
    02316                         //DXT1 is not supported because DXT1 alpha is
    02317                         //seldom used and it's not easily invertable.
    02318                         ilSetError(IL_INVALID_PARAM);
    02319                         return IL_FALSE;
    02320         }
    02321
    02322         Runner = iCurImage->DxtcData;
    02323         for (i = 0; i < numBlocks; ++i, Runner += BlockSize) {
    02324                 InvertAlpha(Runner);
    02325         }
    02326
    02327         return IL_TRUE;
    02328 }
    02329
    02330
    02331
    02332
    02333 #endif//IL_NO_DDS