- Main Page
- Data Structures
- Files

- File List

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

    00001 //-----------------------------------------------------------------------------
    00002 //
    00003 // ImageLib Sources
    00004 // Copyright (C) 2000-2009 by Denton Woods
    00005 // Last modified: 01/28/2009
    00006 //
    00007 // Filename: src-IL/src/il_tpl.c
    00008 //
    00009 // Description: Reads from a Gamecube Texture Palette (.tpl).
    00010 //                Specifications were found at
    00011 //                http://pabut.homeip.net:8000/yagcd/chap14.html.
    00012 //
    00013 //-----------------------------------------------------------------------------
    00014
    00015
    00016 #include "il_internal.h"
    00017 #ifndef IL_NO_TPL
    00018 #include "il_dds.h"
    00019
    00020
    00021 typedef struct TPLHEAD
    00022 {
    00023         ILuint  Magic;
    00024         ILuint  nTextures;
    00025         ILuint  HeaderSize;
    00026 } TPLHEAD;
    00027
    00028 // Data formats
    00029 #define TPL_I4          0
    00030 #define TPL_I8          1
    00031 #define TPL_IA4         2
    00032 #define TPL_IA8         3
    00033 #define TPL_RGB565      4
    00034 #define TPL_RGB5A3      5
    00035 #define TPL_RGBA8       6
    00036 #define TPL_CI4         8
    00037 #define TPL_CI8         9
    00038 #define TPL_CI14X2      10
    00039 #define TPL_CMP         14
    00040
    00041 // Wrapping
    00042 #define TPL_CLAMP       0
    00043 #define TPL_REPEAT      1
    00044 #define TPL_MIRROR      2
    00045
    00046 // Palette entries
    00047 #define TPL_PAL_IA8             0
    00048 #define TPL_PAL_RGB565  1
    00049 #define TPL_PAL_RGB5A3  2
    00050
    00051
    00052 ILboolean iIsValidTpl(void);
    00053 ILboolean iCheckTpl(TPLHEAD *Header);
    00054 ILboolean iLoadTplInternal(void);
    00055 ILboolean TplGetIndexImage(ILimage *Image, ILuint TexOff, ILuint DataFormat);
    00056
    00057
    00059 ILboolean ilIsValidTpl(ILconst_string FileName)
    00060 {
    00061         ILHANDLE        TplFile;
    00062         ILboolean       bTpl = IL_FALSE;
    00063
    00064         if (!iCheckExtension(FileName, IL_TEXT("tpl"))) {
    00065                 ilSetError(IL_INVALID_EXTENSION);
    00066                 return bTpl;
    00067         }
    00068
    00069         TplFile = iopenr(FileName);
    00070         if (TplFile == NULL) {
    00071                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00072                 return bTpl;
    00073         }
    00074
    00075         bTpl = ilIsValidTplF(TplFile);
    00076         icloser(TplFile);
    00077
    00078         return bTpl;
    00079 }
    00080
    00081
    00083 ILboolean ilIsValidTplF(ILHANDLE File)
    00084 {
    00085         ILuint          FirstPos;
    00086         ILboolean       bRet;
    00087
    00088         iSetInputFile(File);
    00089         FirstPos = itell();
    00090         bRet = iIsValidTpl();
    00091         iseek(FirstPos, IL_SEEK_SET);
    00092
    00093         return bRet;
    00094 }
    00095
    00096
    00098 ILboolean ilIsValidTplL(const void *Lump, ILuint Size)
    00099 {
    00100         iSetInputLump(Lump, Size);
    00101         return iIsValidTpl();
    00102 }
    00103
    00104
    00105 // Internal function used to get the TPL header from the current file.
    00106 ILboolean iGetTplHead(TPLHEAD *Header)
    00107 {
    00108         Header->Magic = GetBigUInt();
    00109         Header->nTextures = GetBigUInt();
    00110         Header->HeaderSize = GetBigUInt();
    00111         return IL_TRUE;
    00112 }
    00113
    00114
    00115 // Internal function to get the header and check it.
    00116 ILboolean iIsValidTpl(void)
    00117 {
    00118         TPLHEAD Header;
    00119
    00120         if (!iGetTplHead(&Header))
    00121                 return IL_FALSE;
    00122         iseek(-12, IL_SEEK_CUR);
    00123
    00124         return iCheckTpl(&Header);
    00125 }
    00126
    00127
    00128 // Internal function used to check if the HEADER is a valid TPL header.
    00129 ILboolean iCheckTpl(TPLHEAD *Header)
    00130 {
    00131         // The file signature is 0x0020AF30.
    00132         if (Header->Magic != 0x0020AF30)
    00133                 return IL_FALSE;
    00134         // Only valid header size is 0x0C.
    00135         if (Header->HeaderSize != 0x0C)
    00136                 return IL_FALSE;
    00137         // We have to have at least 1 texture.
    00138         if (Header->nTextures == 0)
    00139                 return IL_FALSE;
    00140
    00141         return IL_TRUE;
    00142 }
    00143
    00144
    00146 ILboolean ilLoadTpl(ILconst_string FileName)
    00147 {
    00148         ILHANDLE        TplFile;
    00149         ILboolean       bTpl = IL_FALSE;
    00150
    00151         TplFile = iopenr(FileName);
    00152         if (TplFile == NULL) {
    00153                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00154                 return bTpl;
    00155         }
    00156
    00157         bTpl = ilLoadTplF(TplFile);
    00158         icloser(TplFile);
    00159
    00160         return bTpl;
    00161 }
    00162
    00163
    00165 ILboolean ilLoadTplF(ILHANDLE File)
    00166 {
    00167         ILuint          FirstPos;
    00168         ILboolean       bRet;
    00169
    00170         iSetInputFile(File);
    00171         FirstPos = itell();
    00172         bRet = iLoadTplInternal();
    00173         iseek(FirstPos, IL_SEEK_SET);
    00174
    00175         return bRet;
    00176 }
    00177
    00178
    00180 ILboolean ilLoadTplL(const void *Lump, ILuint Size)
    00181 {
    00182         iSetInputLump(Lump, Size);
    00183         return iLoadTplInternal();
    00184 }
    00185
    00186
    00187 // Internal function used to load the TPL.
    00188 ILboolean iLoadTplInternal(void)
    00189 {
    00190         TPLHEAD         Header;
    00191         ILimage         *Image/*, *BaseImage*/;
    00192         ILuint          Pos, TexOff, PalOff, DataFormat, Bpp, DataOff, WrapS, WrapT;
    00193         ILuint          x, y, xBlock, yBlock, i, j, k, n;
    00194         ILenum          Format;
    00195         ILushort        Width, Height, ShortPixel;
    00196         ILubyte         BytePixel, CompData[8];
    00197         Color8888       colours[4], *col;
    00198         ILushort        color_0, color_1;
    00199         ILuint          bitmask, Select;
    00200
    00201         if (iCurImage == NULL) {
    00202                 ilSetError(IL_ILLEGAL_OPERATION);
    00203                 return IL_FALSE;
    00204         }
    00205         Image = iCurImage;  // Top-level image
    00206
    00207         if (!iGetTplHead(&Header))
    00208                 return IL_FALSE;
    00209         if (!iCheckTpl(&Header)) {
    00210                 ilSetError(IL_INVALID_FILE_HEADER);
    00211                 return IL_FALSE;
    00212         }
    00213
    00214         // Points to the beginning of the texture header directory.
    00215         Pos = itell();
    00216
    00217         for (n = 0; n < Header.nTextures; n++) {
    00218                 // Go back to the texture header directory for texture number n+1.
    00219                 iseek(Pos + n * 8, IL_SEEK_SET);
    00220                 TexOff = GetBigUInt();
    00221                 PalOff = GetBigUInt();
    00222                 // Go to the texture header.
    00223                 if (iseek(TexOff, IL_SEEK_SET))
    00224                         return IL_FALSE;
    00225
    00226                 Height = GetBigUShort();
    00227                 Width = GetBigUShort();
    00228                 // It looks like files actually have n-1 images, with the nth one having 0 height and width.
    00229                 if (Width == 0 || Height == 0) {
    00230                         // If this is our first image, however, we error out.
    00231                         if (Image == iCurImage) {
    00232                                 ilSetError(IL_ILLEGAL_FILE_VALUE);
    00233                                 return IL_FALSE;
    00234                         }
    00235                         // Break out of our for loop and run ilFixImages on the images.
    00236                         break;
    00237                 }
    00238
    00239                 DataFormat = GetBigUInt();
    00240                 TexOff = GetBigUInt();
    00241                 WrapS = GetBigUInt();
    00242                 WrapT = GetBigUInt();
    00243                 if (WrapS == TPL_REPEAT || WrapS == TPL_MIRROR) {
    00244                         // By the specs, repeated and mirrored textures must have dimensions of power of 2.
    00245                         if ((Width != ilNextPower2(Width)) || (Height != ilNextPower2(Height))) {
    00246                                 ilSetError(IL_ILLEGAL_FILE_VALUE);
    00247                                 return IL_FALSE;
    00248                         }
    00249                 }
    00250
    00251                 // Go to the actual texture data.
    00252                 if (iseek(TexOff, IL_SEEK_SET))
    00253                         return IL_FALSE;
    00254
    00255                 switch (DataFormat)
    00256                 {
    00257                         case TPL_I4:
    00258                         case TPL_I8:
    00259                                 Format = IL_LUMINANCE;
    00260                                 Bpp = 1;
    00261                                 break;
    00262                         case TPL_IA4:
    00263                         case TPL_IA8:
    00264                                 Format = IL_LUMINANCE_ALPHA;
    00265                                 Bpp = 1;
    00266                                 break;
    00267                         case TPL_RGB565:
    00268                                 Format = IL_RGB;
    00269                                 Bpp = 3;
    00270                                 break;
    00271                         case TPL_RGB5A3:
    00272                                 Format = IL_RGBA;
    00273                                 Bpp = 4;
    00274                                 break;
    00275                         case TPL_RGBA8:
    00276                                 Format = IL_RGBA;
    00277                                 Bpp = 4;
    00278                                 break;
    00279                         case TPL_CI4:
    00280                         case TPL_CI8:
    00281                                 Format = IL_COLOR_INDEX;
    00282                                 Bpp = 1;
    00283                                 break;
    00284                         case TPL_CI14X2:
    00285                                 Format = IL_RGBA;
    00286                                 Bpp = 3;
    00287                                 break;
    00288                         case TPL_CMP:
    00289                                 Format = IL_RGBA;
    00290                                 Bpp = 4;
    00291                                 break;
    00292
    00293                         default:
    00294                                 ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00295                                 return IL_FALSE;
    00296                 }
    00297
    00298                 if (Image == iCurImage) {  // This is our first image.
    00299                         if (!ilTexImage(Width, Height, 1, Bpp, Format, IL_UNSIGNED_BYTE, NULL))
    00300                                 return IL_FALSE;
    00301                 }
    00302                 else {
    00303                         Image->Next = ilNewImageFull(Width, Height, 1, Bpp, Format, IL_UNSIGNED_BYTE, NULL);
    00304                         if (Image->Next == NULL)
    00305                                 return IL_FALSE;
    00306                         Image = Image->Next;
    00307                 }
    00308                 Image->Origin = IL_ORIGIN_UPPER_LEFT;  // Origins are always fixed here.
    00309
    00310                 switch (DataFormat)
    00311                 {
    00312                         case TPL_I4:
    00313                                 // 8x8 tiles of 4-bit intensity values
    00314                                 for (y = 0; y < Image->Height; y += 8) {
    00315                                         for (x = 0; x < Image->Width; x += 8) {
    00316                                                 for (yBlock = 0; yBlock < 8; yBlock++) {
    00317                                                         if ((y + yBlock) >= Image->Height) {
    00318                                                                 iseek(8, IL_SEEK_CUR);  // Entire row of pad bytes skipped.
    00319                                                                 continue;
    00320                                                         }
    00321                                                         DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
    00322                                                         for (xBlock = 0; xBlock < 8; xBlock += 2) {
    00323                                                                 BytePixel = igetc();
    00324                                                                 if ((x + xBlock) >= Image->Width)
    00325                                                                         continue;  // Already read the pad byte.
    00326                                                                 Image->Data[DataOff] = (BytePixel & 0xF0) | (BytePixel & 0xF0) >> 4;
    00327                                                                 DataOff++;
    00328                                                                 // We have to do this check again, so we do not go past the last pixel in the image (ex. 1 pixel wide image).
    00329                                                                 if ((x + xBlock) >= Image->Width)
    00330                                                                         continue;  // Already read the pad byte.
    00331                                                                 Image->Data[DataOff+1] = (BytePixel & 0x0F) << 4 | (BytePixel & 0x0F);
    00332                                                                 DataOff++;
    00333                                                         }
    00334                                                 }
    00335                                         }
    00336                                 }
    00337                                 break;
    00338
    00339                         case TPL_I8:
    00340                                 // 8x4 tiles of 8-bit intensity values
    00341                                 for (y = 0; y < Image->Height; y += 4) {
    00342                                         for (x = 0; x < Image->Width; x += 8) {
    00343                                                 for (yBlock = 0; yBlock < 4; yBlock++) {
    00344                                                         if ((y + yBlock) >= Image->Height) {
    00345                                                                 iseek(8, IL_SEEK_CUR);  // Entire row of pad bytes skipped.
    00346                                                                 continue;
    00347                                                         }
    00348                                                         DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
    00349                                                         for (xBlock = 0; xBlock < 8; xBlock++) {
    00350                                                                 if ((x + xBlock) >= Image->Width) {
    00351                                                                         igetc();  // Skip the pad byte.
    00352                                                                         continue;
    00353                                                                 }
    00354                                                                 Image->Data[DataOff] = igetc();  // Luminance value
    00355                                                                 DataOff++;
    00356                                                         }
    00357                                                 }
    00358                                         }
    00359                                 }
    00360                                 break;
    00361
    00362                         case TPL_IA4:
    00363                                 // 8x4 tiles of 4-bit intensity and 4-bit alpha values
    00364                                 for (y = 0; y < Image->Height; y += 4) {
    00365                                         for (x = 0; x < Image->Width; x += 8) {
    00366                                                 for (yBlock = 0; yBlock < 4; yBlock++) {
    00367                                                         if ((y + yBlock) >= Image->Height) {
    00368                                                                 iseek(8, IL_SEEK_CUR);  // Entire row of pad bytes skipped.
    00369                                                                 continue;
    00370                                                         }
    00371                                                         DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
    00372                                                         for (xBlock = 0; xBlock < 8; xBlock += 2) {
    00373                                                                 BytePixel = igetc();
    00374                                                                 if ((x + xBlock) >= Image->Width)
    00375                                                                         continue;  // Already read the pad byte.
    00376                                                                 Image->Data[DataOff] = (BytePixel & 0xF0) | (BytePixel & 0xF0) >> 4;
    00377                                                                 Image->Data[DataOff+1] = (BytePixel & 0x0F) << 4 | (BytePixel & 0x0F);
    00378                                                                 DataOff += 2;
    00379                                                         }
    00380                                                 }
    00381                                         }
    00382                                 }
    00383                                 break;
    00384
    00385                         case TPL_IA8:
    00386                                 // 4x4 tiles of 8-bit intensity and 8-bit alpha values
    00387                                 for (y = 0; y < Image->Height; y += 4) {
    00388                                         for (x = 0; x < Image->Width; x += 4) {
    00389                                                 for (yBlock = 0; yBlock < 4; yBlock++) {
    00390                                                         if ((y + yBlock) >= Image->Height) {
    00391                                                                 iseek(8, IL_SEEK_CUR);  // Entire row of pad bytes skipped.
    00392                                                                 continue;
    00393                                                         }
    00394                                                         DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
    00395                                                         for (xBlock = 0; xBlock < 4; xBlock += 2) {
    00396                                                                 if ((x + xBlock) >= Image->Width) {
    00397                                                                         iseek(2, IL_SEEK_CUR);  // Skip the pad bytes.
    00398                                                                         continue;
    00399                                                                 }
    00400                                                                 Image->Data[DataOff] = igetc();
    00401                                                                 Image->Data[DataOff+1] = igetc();
    00402                                                                 DataOff += 2;
    00403                                                         }
    00404                                                 }
    00405                                         }
    00406                                 }
    00407                                 break;
    00408
    00409                         case TPL_RGB565:
    00410                                 // 4x4 tiles of RGB565 data
    00411                                 for (y = 0; y < Image->Height; y += 4) {
    00412                                         for (x = 0; x < Image->Width; x += 4) {
    00413                                                 for (yBlock = 0; yBlock < 4; yBlock++) {
    00414                                                         if ((y + yBlock) >= Image->Height) {
    00415                                                                 iseek(8, IL_SEEK_CUR);  // Entire row of pad bytes skipped.
    00416                                                                 continue;
    00417                                                         }
    00418                                                         DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
    00419                                                         for (xBlock = 0; xBlock < 4; xBlock++) {
    00420                                                                 ShortPixel = GetBigUShort();
    00421                                                                 if ((x + xBlock) >= Image->Width)
    00422                                                                         continue;  // Already read the pad byte.
    00423                                                                 Image->Data[DataOff] = ((ShortPixel & 0xF800) >> 8) | ((ShortPixel & 0xE000) >> 13); // Red
    00424                                                                 Image->Data[DataOff+1] = ((ShortPixel & 0x7E0) >> 3) | ((ShortPixel & 0x600) >> 9); // Green
    00425                                                                 Image->Data[DataOff+2] = ((ShortPixel & 0x1f) << 3) | ((ShortPixel & 0x1C) >> 2); // Blue
    00426                                                                 DataOff += 3;
    00427                                                         }
    00428                                                 }
    00429                                         }
    00430                                 }
    00431                                 break;
    00432
    00433                         case TPL_RGB5A3:
    00434                                 // 4x4 tiles of either RGB5 or RGB4A3 depending on the MSB. 0x80
    00435                                 for (y = 0; y < Image->Height; y += 4) {
    00436                                         for (x = 0; x < Image->Width; x += 4) {
    00437                                                 for (yBlock = 0; yBlock < 4; yBlock++) {
    00438                                                         if ((y + yBlock) >= Image->Height) {
    00439                                                                 iseek(8, IL_SEEK_CUR);  // Entire row of pad bytes skipped.
    00440                                                                 continue;
    00441                                                         }
    00442                                                         DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
    00443                                                         for (xBlock = 0; xBlock < 4; xBlock++) {
    00444                                                                 ShortPixel = GetBigUShort();
    00445                                                                 if ((x + xBlock) >= Image->Width)
    00446                                                                         continue;  // Already read the pad byte.
    00447
    00448                                                                 if (ShortPixel & 0x8000) {  // Check MSB.
    00449                                                                         // We have RGB5.
    00450                                                                         Image->Data[DataOff] = ((ShortPixel & 0x7C00) >> 7) | ((ShortPixel & 0x7000) >> 12); // Red
    00451                                                                         Image->Data[DataOff+1] = ((ShortPixel & 0x3E0) >> 2) | ((ShortPixel & 0x380) >> 7); // Green
    00452                                                                         Image->Data[DataOff+2] = ((ShortPixel & 0x1F) << 3) | ((ShortPixel & 0x1C) >> 2); // Blue
    00453                                                                         Image->Data[DataOff+3] = 0xFF;  // I am just assuming that it is opaque.
    00454                                                                 }
    00455                                                                 else {
    00456                                                                         // We have RGB4A3.
    00457                                                                         Image->Data[DataOff] = ((ShortPixel & 0x7800) >> 7) | ((ShortPixel & 0x7800) >> 11); // Red
    00458                                                                         Image->Data[DataOff+1] = ((ShortPixel & 0x0780) >> 3) | ((ShortPixel & 0x0780) >> 7); // Green
    00459                                                                         Image->Data[DataOff+2] = ((ShortPixel & 0x0078) << 1) | ((ShortPixel & 0x0078) >> 3); // Blue
    00460                                                                         Image->Data[DataOff+3] = ((ShortPixel & 0x07) << 5) | ((ShortPixel & 0x07) << 2) | (ShortPixel >> 1); // Alpha
    00461                                                                 }
    00462                                                                 DataOff += 3;
    00463                                                         }
    00464                                                 }
    00465                                         }
    00466                                 }
    00467                                 break;
    00468
    00469                         case TPL_RGBA8:
    00470                                 // 4x4 tiles of RGBA data
    00471                                 for (y = 0; y < Image->Height; y += 4) {
    00472                                         for (x = 0; x < Image->Width; x += 4) {
    00473                                                 for (yBlock = 0; yBlock < 4; yBlock++) {
    00474                                                         // Skip pad bytes at the bottom of the tile if any.
    00475                                                         if ((y + yBlock) >= Image->Height) {
    00476                                                                 iseek(16, IL_SEEK_CUR);  // Entire row of pad bytes skipped
    00477                                                                 continue;
    00478                                                         }
    00479
    00480                                                         // First it has the AR data.
    00481                                                         DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
    00482                                                         for (xBlock = 0; xBlock < 4; xBlock++) {
    00483                                                                 if ((x + xBlock) >= Image->Width) {
    00484                                                                         iseek(2, IL_SEEK_CUR);  // Skip pad bytes.
    00485                                                                         continue;
    00486                                                                 }
    00487                                                                 Image->Data[DataOff+3] = igetc();  // Alpha
    00488                                                                 Image->Data[DataOff] = igetc();  // Red
    00489                                                                 DataOff += 3;
    00490                                                         }
    00491
    00492                                                         // Then it has the GB data.
    00493                                                         DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
    00494                                                         for (xBlock = 0; xBlock < 4 && x + xBlock < Image->Width; xBlock++) {
    00495                                                                 if ((x + xBlock) >= Image->Width) {
    00496                                                                         iseek(2, IL_SEEK_CUR);  // Skip pad bytes.
    00497                                                                         continue;
    00498                                                                 }
    00499                                                                 Image->Data[DataOff+1] = igetc();  // Green
    00500                                                                 Image->Data[DataOff+2] = igetc();  // Blue
    00501                                                                 DataOff += 3;
    00502                                                         }
    00503                                                 }
    00504                                         }
    00505                                 }
    00506                                 break;
    00507
    00508                         case TPL_CI4:
    00509                         case TPL_CI8:
    00510                         case TPL_CI14X2:
    00511                                 // Seek to the palette header.
    00512                                 if (iseek(PalOff, IL_SEEK_SET))
    00513                                         return IL_FALSE;
    00514                                 if (!TplGetIndexImage(Image, TexOff, DataFormat))
    00515                                         return IL_FALSE;
    00516                                 break;
    00517
    00518                         case TPL_CMP:
    00519                                 // S3TC 2x2 blocks of 4x4 tiles.  I am assuming that this is DXT1, since it is not specified in the specs.
    00520                                 //  Most of this ended up being copied from il_dds.c, from the DecompressDXT1 function.
    00521                                 //@TODO: Make this/that code a bit more modular.
    00522                                 for (y = 0; y < Image->Height; y += 8) {
    00523                                         for (x = 0; x < Image->Width; x += 8) {
    00524                                                 for (yBlock = 0; yBlock < 8 && (y + yBlock) < Image->Height; yBlock += 4) {
    00525                                                         for (xBlock = 0; xBlock < 8 && (x + xBlock) < Image->Width; xBlock += 4) {
    00526                                                                 if (iread(CompData, 1, 8) != 8)
    00527                                                                         return IL_FALSE;  //@TODO: Need to do any cleanup here?
    00528                                                                 color_0 = *((ILushort*)CompData);
    00529                                                                 UShort(&color_0);
    00530                                                                 color_1 = *((ILushort*)(CompData + 2));
    00531                                                                 UShort(&color_1);
    00532                                                                 DxtcReadColor(color_0, colours);
    00533                                                                 DxtcReadColor(color_1, colours + 1);
    00534                                                                 bitmask = ((ILuint*)CompData)[1];
    00535                                                                 UInt(&bitmask);
    00536
    00537                                                                 if (color_0 > color_1) {
    00538                                                                         // Four-color block: derive the other two colors.
    00539                                                                         // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
    00540                                                                         // These 2-bit codes correspond to the 2-bit fields
    00541                                                                         // stored in the 64-bit block.
    00542                                                                         colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
    00543                                                                         colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
    00544                                                                         colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
    00545                                                                         //colours[2].a = 0xFF;
    00546
    00547                                                                         colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
    00548                                                                         colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
    00549                                                                         colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
    00550                                                                         colours[3].a = 0xFF;
    00551                                                                 }
    00552                                                                 else {
    00553                                                                         // Three-color block: derive the other color.
    00554                                                                         // 00 = color_0,  01 = color_1,  10 = color_2,
    00555                                                                         // 11 = transparent.
    00556                                                                         // These 2-bit codes correspond to the 2-bit fields
    00557                                                                         // stored in the 64-bit block.
    00558                                                                         colours[2].b = (colours[0].b + colours[1].b) / 2;
    00559                                                                         colours[2].g = (colours[0].g + colours[1].g) / 2;
    00560                                                                         colours[2].r = (colours[0].r + colours[1].r) / 2;
    00561                                                                         //colours[2].a = 0xFF;
    00562
    00563                                                                         colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
    00564                                                                         colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
    00565                                                                         colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
    00566                                                                         colours[3].a = 0x00;
    00567                                                                 }
    00568
    00569                                                                 for (j = 0, k = 0; j < 4; j++) {
    00570                                                                         for (i = 0; i < 4; i++, k++) {
    00571                                                                                 Select = (bitmask & (0x03 << k*2)) >> k*2;
    00572                                                                                 col = &colours[Select];
    00573
    00574                                                                                 if (((x + xBlock + i) < Image->Width) && ((y + yBlock + j) < Image->Height)) {
    00575                                                                                         DataOff = (y + yBlock + j) * Image->Bps + (x + xBlock + i) * Image->Bpp;
    00576                                                                                         Image->Data[DataOff + 0] = col->r;
    00577                                                                                         Image->Data[DataOff + 1] = col->g;
    00578                                                                                         Image->Data[DataOff + 2] = col->b;
    00579                                                                                         Image->Data[DataOff + 3] = col->a;
    00580                                                                                 }
    00581                                                                         }
    00582                                                                 }
    00583                                                         }
    00584                                                 }
    00585                                         }
    00586                                 }
    00587                                 break;
    00588                 }
    00589         }
    00590
    00591         return ilFixImage();
    00592 }
    00593
    00594
    00595 ILboolean TplGetIndexImage(ILimage *Image, ILuint TexOff, ILuint DataFormat)
    00596 {
    00597         ILushort        NumPal, ShortPixel;
    00598         ILubyte         LumVal, BytePixel;
    00599         ILuint          PalFormat, PalOff, PalBpp, DataOff;
    00600         ILuint          x, y, xBlock, yBlock, i;
    00601
    00602         NumPal = GetBigUShort();
    00603         iseek(2, IL_SEEK_CUR);  // Do we need to do anything with the 'unpacked' entry?  I see nothing in the specs about it.
    00604         PalFormat = GetBigUInt();
    00605
    00606         // Now we have to find out where the actual palette data is stored.
    00607         //@TODO: Do we need to set any errors here?
    00608         PalOff = GetBigUInt();
    00609         if (iseek(PalOff, IL_SEEK_SET))
    00610                 return IL_FALSE;
    00611
    00612         switch (PalFormat)
    00613         {
    00614                 case TPL_PAL_IA8:
    00615                         Image->Pal.Palette = (ILubyte*)ialloc(NumPal * 4);
    00616                         if (Image->Pal.Palette == NULL)
    00617                                 return IL_FALSE;
    00618                         Image->Pal.PalType = IL_PAL_RGBA32;  //@TODO: Use this format natively.
    00619                         Image->Pal.PalSize = NumPal * 4;
    00620                         PalBpp = 4;
    00621
    00622                         for (i = 0; i < NumPal; i++) {
    00623                                 LumVal = igetc();
    00624                                 //@TODO: Do proper conversion of luminance, or support this format natively.
    00625                                 Image->Pal.Palette[i * 4] = LumVal;  // Assign the luminance value.
    00626                                 Image->Pal.Palette[i * 4 + 1] = LumVal;
    00627                                 Image->Pal.Palette[i * 4 + 2] = LumVal;
    00628                                 Image->Pal.Palette[i * 4 + 3] = igetc();  // Get alpha value.
    00629                         }
    00630                         break;
    00631
    00632                 case TPL_PAL_RGB565:
    00633                         Image->Pal.Palette = (ILubyte*)ialloc(NumPal * 3);
    00634                         if (Image->Pal.Palette == NULL)
    00635                                 return IL_FALSE;
    00636                         Image->Pal.PalType = IL_PAL_RGB24;
    00637                         Image->Pal.PalSize = NumPal * 3;
    00638                         PalBpp = 3;
    00639
    00640                         for (i = 0; i < NumPal; i++) {
    00641                                 ShortPixel = GetBigUShort();
    00642                                 // This is mostly the same code as in the TPL_RGB565 case.
    00643                                 Image->Pal.Palette[i*3] = ((ShortPixel & 0xF800) >> 8) | ((ShortPixel & 0xE000) >> 13); // Red
    00644                                 Image->Pal.Palette[i*3+1] = ((ShortPixel & 0x7E0) >> 3) | ((ShortPixel & 0x600) >> 9); // Green
    00645                                 Image->Pal.Palette[i*3+2] = ((ShortPixel & 0x1f) << 3) | ((ShortPixel & 0x1C) >> 2); // Blue
    00646                         }
    00647                         break;
    00648
    00649                 case TPL_PAL_RGB5A3:
    00650                         Image->Pal.Palette = (ILubyte*)ialloc(NumPal * 4);
    00651                         if (Image->Pal.Palette == NULL)
    00652                                 return IL_FALSE;
    00653                         Image->Pal.PalType = IL_PAL_RGBA32;
    00654                         Image->Pal.PalSize = NumPal * 4;
    00655                         PalBpp = 4;
    00656
    00657                         for (i = 0; i < NumPal; i++) {
    00658                                 ShortPixel = GetBigUShort();
    00659                                 // This is mostly the same code as in the TPL_RGB565 case.
    00660                                 if (ShortPixel & 0x8000) {  // Check MSB.
    00661                                         // We have RGB5.
    00662                                         Image->Pal.Palette[i*4] = ((ShortPixel & 0x7C00) >> 7) | ((ShortPixel & 0x7000) >> 12); // Red
    00663                                         Image->Pal.Palette[i*4+1] = ((ShortPixel & 0x3E0) >> 2) | ((ShortPixel & 0x380) >> 7); // Green
    00664                                         Image->Pal.Palette[i*4+2] = ((ShortPixel & 0x1F) << 3) | ((ShortPixel & 0x1C) >> 2); // Blue
    00665                                         Image->Pal.Palette[i*4+3] = 0xFF;  // I am just assuming that it is opaque.
    00666                                 }
    00667                                 else {
    00668                                         // We have RGB4A3.
    00669                                         Image->Pal.Palette[i*4] = ((ShortPixel & 0x7800) >> 7) | ((ShortPixel & 0x7800) >> 11); // Red
    00670                                         Image->Pal.Palette[i*4+1] = ((ShortPixel & 0x0780) >> 3) | ((ShortPixel & 0x0780) >> 7); // Green
    00671                                         Image->Pal.Palette[i*4+2] = ((ShortPixel & 0x0078) << 1) | ((ShortPixel & 0x0078) >> 3); // Blue
    00672                                         Image->Pal.Palette[i*4+3] = ((ShortPixel & 0x07) << 5) | ((ShortPixel & 0x07) << 2) | (ShortPixel >> 1); // Alpha
    00673                                 }
    00674                         }
    00675                         break;
    00676
    00677                 default:
    00678                         ilSetError(IL_ILLEGAL_FILE_VALUE);
    00679                         return IL_FALSE;
    00680         }
    00681
    00682         // Go back to the texture data.
    00683         if (iseek(TexOff, IL_SEEK_SET))
    00684                 return IL_FALSE;
    00685
    00686         switch (DataFormat)
    00687         {
    00688                 case TPL_CI4:
    00689                         // 8x8 tiles of 4-bit color indices
    00690                         //  This is the exact same code as the TPL_I4 case.
    00691                         for (y = 0; y < Image->Height; y += 8) {
    00692                                 for (x = 0; x < Image->Width; x += 8) {
    00693                                         for (yBlock = 0; yBlock < 8; yBlock++) {
    00694                                                 if ((y + yBlock) >= Image->Height) {
    00695                                                         iseek(8, IL_SEEK_CUR);  // Entire row of pad bytes skipped.
    00696                                                         continue;
    00697                                                 }
    00698                                                 DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
    00699                                                 for (xBlock = 0; xBlock < 8; xBlock += 2) {
    00700                                                         BytePixel = igetc();
    00701                                                         if ((x + xBlock) >= Image->Width)
    00702                                                                 continue;  // Already read the pad byte.
    00703                                                         Image->Data[DataOff] = (BytePixel & 0xF0) | (BytePixel & 0xF0) >> 4;
    00704                                                         DataOff++;
    00705                                                         // We have to do this check again, so we do not go past the last pixel in the image (ex. 1 pixel wide image).
    00706                                                         if ((x + xBlock) >= Image->Width)
    00707                                                                 continue;  // Already read the pad byte.
    00708                                                         Image->Data[DataOff+1] = (BytePixel & 0x0F) << 4 | (BytePixel & 0x0F);
    00709                                                         DataOff++;
    00710                                                 }
    00711                                         }
    00712                                 }
    00713                         }
    00714                         break;
    00715
    00716                 case TPL_CI8:
    00717                         // 8x4 tiles of 8-bit intensity values
    00718                         //  This is the exact same code as the TPL_I8 case.
    00719                         for (y = 0; y < Image->Height; y += 4) {
    00720                                 for (x = 0; x < Image->Width; x += 8) {
    00721                                         for (yBlock = 0; yBlock < 4; yBlock++) {
    00722                                                 if ((y + yBlock) >= Image->Height) {
    00723                                                         iseek(8, IL_SEEK_CUR);  // Entire row of pad bytes skipped.
    00724                                                         continue;
    00725                                                 }
    00726                                                 DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
    00727                                                 for (xBlock = 0; xBlock < 8; xBlock++) {
    00728                                                         if ((x + xBlock) >= Image->Width) {
    00729                                                                 igetc();  // Skip the pad byte.
    00730                                                                 continue;
    00731                                                         }
    00732                                                         Image->Data[DataOff] = igetc();  // Color index
    00733                                                         DataOff++;
    00734                                                 }
    00735                                         }
    00736                                 }
    00737                         }
    00738                         break;
    00739
    00740
    00741                 //@TODO: Convert to more formats than just RGBA.
    00742                 case TPL_CI14X2:
    00743                         // 4x4 tiles of 14-bit indices into a palette.  Not supported at all in DevIL, since
    00744                         //  it has a huge palette (> 256 colors).  Convert to RGBA.
    00745                         for (y = 0; y < Image->Height; y += 4) {
    00746                                 for (x = 0; x < Image->Width; x += 4) {
    00747                                         for (yBlock = 0; yBlock < 4; yBlock++) {
    00748                                                 if ((y + yBlock) >= Image->Height) {
    00749                                                         iseek(8, IL_SEEK_CUR);  // Entire row of pad bytes skipped.
    00750                                                         continue;
    00751                                                 }
    00752                                                 DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
    00753                                                 for (xBlock = 0; xBlock < 4; xBlock++) {
    00754                                                         if ((x + xBlock) >= Image->Width) {
    00755                                                                 GetBigUShort();  // Skip the pad short.
    00756                                                                 continue;
    00757                                                         }
    00758                                                         ShortPixel = GetBigUShort();
    00759                                                         ShortPixel >>= 2;  // Lower 2 bits are padding bits.
    00760                                                         Image->Data[DataOff] = Image->Pal.Palette[ShortPixel * PalBpp];
    00761                                                         Image->Data[DataOff+1] = Image->Pal.Palette[ShortPixel * PalBpp + 1];
    00762                                                         Image->Data[DataOff+2] = Image->Pal.Palette[ShortPixel * PalBpp + 2];
    00763                                                         if (PalFormat == TPL_PAL_RGB565)
    00764                                                                 Image->Data[DataOff+3] = 0xFF;
    00765                                                         else
    00766                                                                 Image->Data[DataOff+3] = Image->Pal.Palette[ShortPixel * PalBpp + 3];
    00767                                                         DataOff++;
    00768                                                 }
    00769                                         }
    00770                                 }
    00771                         }
    00772                         // Get rid of the palette, since we no longer need it.
    00773                         ifree(Image->Pal.Palette);
    00774                         Image->Pal.PalType = IL_PAL_NONE;
    00775                         Image->Pal.PalSize = 0;
    00776                         break;
    00777
    00778         }
    00779
    00780         return IL_TRUE;
    00781 }
    00782 #endif//IL_NO_TPL