- Main Page
- Data Structures
- Files

- File List

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

    00001 //-----------------------------------------------------------------------------
    00002 //
    00003 // ImageLib Sources
    00004 // Last modified: 01/20/2009
    00005 //
    00006 // Filename: src-IL/src/il_iff.c
    00007 //
    00008 // Description: Reads from an .iff file.  Contribution from GAIA:
    00009 //                              http://gaia.fdi.ucm.es/grupo/projects/javy/devzone.html#DevILNotes.
    00010 //
    00011 //-----------------------------------------------------------------------------
    00012
    00013 #include "il_internal.h"
    00014
    00015 #ifndef IL_NO_IFF
    00016
    00017 // Chunk type, data and functions:
    00018 typedef struct _iff_chunk {
    00019         ILuint  tag;
    00020         ILuint  start;
    00021         ILuint  size;
    00022         ILuint  chunkType;
    00023 } iff_chunk;
    00024
    00025 #define CHUNK_STACK_SIZE (32)
    00026 static iff_chunk chunkStack[CHUNK_STACK_SIZE];
    00027 static int chunkDepth = -1;
    00028
    00029 iff_chunk iff_begin_read_chunk();
    00030 void iff_end_read_chunk();
    00031 char *iff_read_data(int size);
    00032 ILboolean iLoadIffInternal(void);
    00033
    00034
    00035 /* Define the IFF tags we are looking for in the file. */
    00036 const ILuint IFF_TAG_CIMG = ('C' << 24) | ('I' << 16) | ('M' << 8) | ('G');
    00037 const ILuint IFF_TAG_FOR4 = ('F' << 24) | ('O' << 16) | ('R' << 8) | ('4');
    00038 const ILuint IFF_TAG_TBHD = ('T' << 24) | ('B' << 16) | ('H' << 8) | ('D');
    00039 const ILuint IFF_TAG_TBMP = ('T' << 24) | ('B' << 16) | ('M' << 8) | ('P');
    00040 const ILuint IFF_TAG_RGBA = ('R' << 24) | ('G' << 16) | ('B' << 8) | ('A');
    00041 const ILuint IFF_TAG_CLPZ = ('C' << 24) | ('L' << 16) | ('P' << 8) | ('Z');
    00042 const ILuint IFF_TAG_ESXY = ('E' << 24) | ('S' << 16) | ('X' << 8) | ('Y');
    00043 const ILuint IFF_TAG_ZBUF = ('Z' << 24) | ('B' << 16) | ('U' << 8) | ('F');
    00044 const ILuint IFF_TAG_BLUR = ('B' << 24) | ('L' << 16) | ('U' << 8) | ('R');
    00045 const ILuint IFF_TAG_BLRT = ('B' << 24) | ('L' << 16) | ('R' << 8) | ('T');
    00046 const ILuint IFF_TAG_HIST = ('H' << 24) | ('I' << 16) | ('S' << 8) | ('T');
    00047
    00048 // Flags
    00049 #define RGB_FLAG     (1)
    00050 #define ALPHA_FLAG   (2)
    00051 #define ZBUFFER_FLAG (4)
    00052
    00053 // Function for decompress the file.
    00054 char *iff_decompress_rle(ILuint numBytes, char *compressedData,
    00055                                                         ILuint compressedDataSize,
    00056                                                         ILuint *compressedStartIndex);
    00057
    00058 char *iffReadUncompressedTile(ILushort width, ILushort height, ILbyte depth);
    00059 char *iff_decompress_tile_rle(ILushort width, ILushort height, ILushort depth,
    00060                                  char *compressedData, ILuint compressedDataSize);
    00061
    00062
    00064 ILboolean ilLoadIff(const ILstring FileName)
    00065 {
    00066         ILHANDLE iffFile;
    00067         ILboolean ret = IL_FALSE;
    00068
    00069         iffFile = iopenr(FileName);
    00070         if (iffFile == NULL) {
    00071                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00072                 return ret;
    00073         }
    00074         ret = ilLoadIffF(iffFile);
    00075         icloser(iffFile);
    00076         return ret;
    00077 }
    00078
    00079
    00081 ILboolean ilLoadIffF(ILHANDLE File)
    00082 {
    00083         ILuint          FirstPos;
    00084         ILboolean       bRet;
    00085
    00086         iSetInputFile(File);
    00087         FirstPos = itell();
    00088         bRet = iLoadIffInternal();
    00089         iseek(FirstPos, IL_SEEK_SET);
    00090
    00091         return bRet;
    00092 }
    00093
    00094
    00096 ILboolean ilLoadIffL(const void *Lump, ILuint Size)
    00097 {
    00098         iSetInputLump(Lump, Size);
    00099         return iLoadIffInternal();
    00100 }
    00101
    00102 ILboolean iLoadIffInternal(void)
    00103 {
    00104         iff_chunk chunkInfo;
    00105
    00106         // -- Header info.
    00107         ILuint width, height;
    00108         ILuint flags, compress;
    00109         ILushort tiles;
    00110
    00111         ILenum  format;
    00112         ILubyte bpp;
    00113
    00114         ILboolean tileImageDataFound;
    00115
    00116         // -- Initialize the top of the chunk stack.
    00117         chunkDepth = -1;
    00118
    00119         // -- File should begin with a FOR4 chunk of type CIMG
    00120         chunkInfo = iff_begin_read_chunk();
    00121         if ( chunkInfo.chunkType != IFF_TAG_CIMG ) {
    00122                 ilSetError(IL_ILLEGAL_FILE_VALUE);
    00123                 return IL_FALSE;
    00124         }
    00125
    00126
    00127         /*
    00128         * Read the image header
    00129         * OK, we have a FOR4 of type CIMG, look for the following tags
    00130         *               FVER
    00131         *               TBHD    bitmap header, definition of size, etc.
    00132         *               AUTH
    00133         *               DATE
    00134         */
    00135         while (1) {
    00136
    00137                 chunkInfo = iff_begin_read_chunk();
    00138
    00139                 // -- Right now, the only info we need about the image is in TBHD
    00140                 // -- so search this level until we find it.
    00141                 if( chunkInfo.tag == IFF_TAG_TBHD ) {
    00142                         // -- Header chunk found
    00143                         width = GetBigUInt();
    00144                         height = GetBigUInt();
    00145                         GetBigShort(); // -- Don't support
    00146                         GetBigShort(); // -- Don't support
    00147                         flags = GetBigUInt();
    00148                         GetBigShort(); // -- Don't support
    00149                         tiles = GetBigUShort();
    00150                         compress        = GetBigUInt();
    00151
    00152                         iff_end_read_chunk();
    00153
    00154                         if( compress > 1 ) {
    00155                                 ilSetError(IL_ILLEGAL_FILE_VALUE);
    00156                                 return  IL_FALSE;
    00157                         }
    00158                                 break;
    00159                 } else
    00160                         iff_end_read_chunk();
    00161         } /* END find TBHD while loop */
    00162
    00163         if (!(flags & RGB_FLAG)) {
    00164                 ilSetError(IL_ILLEGAL_FILE_VALUE);
    00165                 return  IL_FALSE;
    00166         }
    00167
    00168         if (flags & ALPHA_FLAG) {
    00169                 format = IL_RGBA; bpp = 4;
    00170         } else {
    00171                 format = IL_RGB; bpp = 3;
    00172         }
    00173
    00174         if (!ilTexImage(width, height, 1, bpp, format, IL_UNSIGNED_BYTE, NULL))
    00175                 return IL_FALSE;
    00176
    00177         iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
    00178
    00179         tileImageDataFound = IL_FALSE;
    00180
    00181         while (!tileImageDataFound) {
    00182                 ILuint tileImage;
    00183                 ILuint tileZ;
    00184
    00185                 chunkInfo = iff_begin_read_chunk();
    00186
    00187                 /*
    00188                  * OK, we have a FOR4 of type TBMP, (embedded FOR4)
    00189                  * look for the following tags
    00190                  *              RGBA    color data,     RLE compressed tiles of 32 bbp data
    00191                  *              ZBUF    z-buffer data, 32 bit float values
    00192                  *              CLPZ    depth map specific, clipping planes, 2 float values
    00193                  *              ESXY    depth map specific, eye x-y ratios, 2 float values
    00194                  *              HIST
    00195                  *              VERS
    00196                  *              FOR4 <size>     BLUR (twice embedded FOR4)
    00197                  */
    00198                 if (chunkInfo.chunkType != IFF_TAG_TBMP) {
    00199                         iff_end_read_chunk();
    00200                         continue;
    00201                 }
    00202                 tileImageDataFound = IL_TRUE;
    00203                 tileImage = 0;  // Si no RGBA, tileImage = tiles...
    00204                 if (flags & ZBUFFER_FLAG)
    00205                         tileZ = 0;
    00206                 else
    00207                         tileZ = tiles;
    00208
    00209                 // Read tiles
    00210                 while ( (tileImage < tiles) || (tileZ < tiles)) {
    00211                         char     *tileData;
    00212                         ILushort x1, x2, y1, y2, tile_width, tile_height;
    00213                         ILuint remainingDataSize;
    00214                         ILushort        tile_area;
    00215                         ILuint  tileCompressed;
    00216
    00217                         chunkInfo = iff_begin_read_chunk();
    00218                         if ((chunkInfo.tag != IFF_TAG_RGBA) && (chunkInfo.tag != IFF_TAG_ZBUF)) {
    00219                                 ilSetError(IL_ILLEGAL_FILE_VALUE);
    00220                                 return IL_FALSE;
    00221                         }
    00222                         x1 = GetBigUShort();    y1 = GetBigUShort();
    00223                         x2 = GetBigUShort();    y2 = GetBigUShort();
    00224
    00225                         remainingDataSize = chunkInfo.size - 4*sizeof(ILushort);
    00226                         tile_width = x2 - x1 + 1;
    00227                         tile_height = y2 - y1 + 1;
    00228                         tile_area = tile_width * tile_height;
    00229
    00230                         if ((ILint)remainingDataSize >= (tile_width * tile_height * bpp))
    00231                                 tileCompressed = 0;
    00232                         else
    00233                                 tileCompressed = 1;
    00234
    00235                         if (chunkInfo.tag == IFF_TAG_RGBA) {
    00236                                 if (tileCompressed) {
    00237                                         char    *data = iff_read_data(remainingDataSize);
    00238                                         if (data) {
    00239                                                 tileData = iff_decompress_tile_rle(tile_width, tile_height,
    00240                                                                                                                         bpp, data, remainingDataSize);
    00241                                                 ifree(data);
    00242                                         }
    00243                                 } else {
    00244                                         tileData = iffReadUncompressedTile(tile_width, tile_height, bpp);
    00245                                 }
    00246
    00247                                 if (tileData) {
    00248                                         // Dump RGBA data to our data structure
    00249                                         ILushort        i;
    00250                                         ILuint          base;
    00251                                         base = bpp*(width * y1 + x1);
    00252                                         for (i = 0; i < tile_height; i++) {
    00253                                                 memcpy(&iCurImage->Data[base + bpp*i*width],
    00254                                                                 &tileData[bpp*i*tile_width],
    00255                                                                 tile_width*bpp*sizeof(char));
    00256                                         }
    00257                                         ifree(tileData);
    00258                                         tileData = NULL;
    00259
    00260                                         iff_end_read_chunk();
    00261                                         tileImage++;
    00262                                 } else
    00263                                         return IL_FALSE;
    00264                         } else if (chunkInfo.tag == IFF_TAG_ZBUF) {
    00265                                 tileZ++;
    00266                                 iff_end_read_chunk();
    00267                         }
    00268
    00269                 }
    00270         }
    00271         ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);
    00272         ilFixImage();
    00273         return IL_TRUE;
    00274 }
    00275
    00276 /*
    00277  * IFF Chunking Routines.
    00278  *
    00279  */
    00280
    00281 iff_chunk iff_begin_read_chunk()
    00282 {
    00283         chunkDepth++;
    00284         if (chunkDepth >= CHUNK_STACK_SIZE){
    00285                 ilSetError(IL_STACK_OVERFLOW);
    00286                 return chunkStack[0];
    00287         }
    00288         if (chunkDepth < 0) {
    00289                 ilSetError(IL_STACK_UNDERFLOW);
    00290                 return chunkStack[0];
    00291         }
    00292
    00293         chunkStack[chunkDepth].start = itell();
    00294         chunkStack[chunkDepth].tag = GetBigInt();
    00295         chunkStack[chunkDepth].size = GetBigInt();
    00296
    00297         if (chunkStack[chunkDepth].tag == IFF_TAG_FOR4) {
    00298                 // -- We have a form, so read the form type tag as well.
    00299                 chunkStack[chunkDepth].chunkType = GetBigInt();
    00300         } else {
    00301                 chunkStack[chunkDepth].chunkType = 0;
    00302         }
    00303
    00304         return chunkStack[chunkDepth];
    00305 }
    00306
    00307 void iff_end_read_chunk()
    00308 {
    00309         ILuint  end;
    00310         int             part;
    00311
    00312         end = chunkStack[chunkDepth].start + chunkStack[chunkDepth].size + 8;
    00313
    00314         if (chunkStack[chunkDepth].chunkType != 0) {
    00315                 end += 4;
    00316         }
    00317         // Add padding
    00318         part = end % 4;
    00319         if (part != 0) {
    00320             end += 4 - part;
    00321         }
    00322
    00323         iseek(end, IL_SEEK_SET);
    00324
    00325         chunkDepth--;
    00326 }
    00327
    00328 char * iff_read_data(int size)
    00329 {
    00330         char *buffer = ialloc(size * sizeof(char));
    00331         if (buffer == NULL)
    00332                 return NULL;
    00333
    00334         if (iread(buffer, size*sizeof(char), 1) != 1) {
    00335                 ifree(buffer);
    00336                 return NULL;
    00337         }
    00338
    00339         return buffer;
    00340 }
    00341
    00342 /*
    00343         IFF decompress functions
    00344 */
    00345
    00346 char *iffReadUncompressedTile(ILushort width, ILushort height, ILbyte depth)
    00347 {
    00348
    00349         char    *data = NULL;
    00350         char    *iniPixel;
    00351         char    *finPixel;
    00352         int             i, j;
    00353         int             tam = width* height * depth * sizeof(char);
    00354
    00355         data = ialloc(tam);
    00356         if (data == NULL)
    00357                 return NULL;
    00358
    00359         if (iread(data, tam, 1) != 1) {
    00360                 ifree(data);
    00361                 return NULL;
    00362         }
    00363
    00364         iniPixel = data;
    00365         for (i = 0; i < tam / depth; i++) {
    00366                 finPixel = iniPixel + depth;
    00367                 for (j = 0; j < (depth /2); j++) {
    00368                         char aux;
    00369                         aux = *iniPixel;
    00370                         *(finPixel--) = *iniPixel;
    00371                         *(iniPixel++) = aux;
    00372                 }
    00373         }
    00374         return data;
    00375 }
    00376
    00377
    00378 char *iff_decompress_tile_rle(ILushort width, ILushort height, ILushort depth,
    00379                                                           char *compressedData, ILuint compressedDataSize)
    00380 {
    00381
    00382         char    *channels[4];
    00383         char    *data;
    00384         int             i, k, row, column;
    00385         ILuint  compressedStart = 0;
    00386
    00387         // Decompress only in RGBA.
    00388         if (depth != 4) {
    00389                 ilSetError(IL_ILLEGAL_FILE_VALUE);
    00390                 return NULL;
    00391         }
    00392
    00393         for (i = depth-1; i >= 0; --i) {
    00394                 channels[i] = iff_decompress_rle(width * height, compressedData,
    00395                                       compressedDataSize, &compressedStart);
    00396                 if (channels[i] == NULL)
    00397                         return NULL;
    00398         }
    00399
    00400     // Build all the channels from the decompression into an RGBA array.
    00401         data = ialloc(width * height * depth * sizeof(char));
    00402         if (data == NULL)
    00403                 return NULL;
    00404
    00405         for (row = 0; row < height; row++)
    00406                 for (column = 0; column < width; column++)
    00407                         for (k = 0; k < depth; k++)
    00408                                 data[depth*(row*width + column) + k] =
    00409                                         channels[k][row*width + column];
    00410
    00411         ifree(channels[0]); ifree(channels[1]);
    00412         ifree(channels[2]); ifree(channels[3]);
    00413
    00414         return data;
    00415 }
    00416
    00417 char *iff_decompress_rle(ILuint numBytes, char *compressedData,
    00418                                                         ILuint compressedDataSize,
    00419                                                         ILuint *compressedStartIndex)
    00420 {
    00421
    00422         char    *data = ialloc(numBytes * sizeof(char));
    00423         unsigned char   nextChar, count;
    00424         int             i;
    00425         ILuint  byteCount = 0;
    00426
    00427         if (data == NULL)
    00428                 return NULL;
    00429
    00430         memset(data, 0, numBytes*sizeof(char));
    00431
    00432         while (byteCount < numBytes) {
    00433                 if (*compressedStartIndex >= compressedDataSize)
    00434                         break;
    00435                 nextChar = compressedData[*compressedStartIndex];
    00436                 (*compressedStartIndex)++;
    00437                 count = (nextChar & 0x7f) + 1;
    00438                 if ((byteCount + count) > numBytes) break;
    00439                 if (nextChar & 0x80) {
    00440                         // Duplication run
    00441                         nextChar = compressedData[*compressedStartIndex];
    00442                         (*compressedStartIndex)++;
    00443                         // assert ((byteCount + count) <= numBytes);
    00444                         for (i = 0; i < count; i++) {
    00445                                 data[byteCount]= nextChar;
    00446                                 byteCount++;
    00447                         }
    00448                 } else {
    00449                         // Verbatim run
    00450                         for (i = 0; i < count; i++) {
    00451                                 data[byteCount] = compressedData[*compressedStartIndex];
    00452                                 (*compressedStartIndex)++;
    00453                                 byteCount++;
    00454                         }
    00455                 }
    00456                 //assert(byteCount <= numBytes);
    00457         }
    00458
    00459         return data;
    00460
    00461 }
    00462
    00463 #endif //IL_NO_IFF