Esempio n. 1
0
void Image_DXTC::Decompress()
{
	VERIFY( m_pCompBytes );

	AllocateDecompBytes();

	VERIFY( m_pDecompBytes );		// must already have allocated memory

	switch( m_CompFormat )
	{
	case PF_DXT1 :
		//TRACE( "Decompressing image format:  DXT1\n" );
		DecompressDXT1();
		break;

	case PF_DXT2 :
		//TRACE( "Decompressing image format:  DXT2\n" );
		DecompressDXT2();
		break;

	case PF_DXT3 :
		//TRACE( "Decompressing image format:  DXT3\n" );
		DecompressDXT3();	
		break;

	case PF_DXT4 :
		//TRACE( "Decompressing image format:  DXT4\n" );
		DecompressDXT4();
		break;

	case PF_DXT5 :
		//TRACE( "Decompressing image format:  DXT5\n" );
		DecompressDXT5();		
		break;

	case PF_UNKNOWN :
		break;
	}
	//. swap R<->B channels
	for (int y=0; y<m_nHeight; y++)
	{
		for (int x=0; x<m_nWidth; x++)
		{
			BYTE*	ptr = m_pDecompBytes + (y*m_nWidth+x)*4;
			swap	(ptr[0],ptr[2]);
		}
	}
}
Esempio n. 2
0
// Internal function used to load the BLP.
ILboolean iLoadBlpInternal(void)
{
    BLP2HEAD	Header;
    ILubyte		*CompData;
    ILimage		*Image;
    ILuint		Mip, j, x, CompSize, AlphaSize, AlphaOff;
    ILint		y;
    ILboolean	BaseCreated = IL_FALSE;
    ILubyte		*DataAndAlpha = NULL, *Palette = NULL, AlphaMask; //, *JpegHeader, *JpegData;

    if (iCurImage == NULL) {
        ilSetError(IL_ILLEGAL_OPERATION);
        return IL_FALSE;
    }

    if (!iGetBlp2Head(&Header)) {
        ilSetError(IL_INVALID_FILE_HEADER);
        return IL_FALSE;
    }
    if (!iCheckBlp2(&Header)) {
        goto check_blp1;
    }

//@TODO: Remove this!
    if (Header.Type != BLP_TYPE_DXTC_RAW)
        return IL_FALSE;

    switch (Header.Compression)
    {
    case BLP_RAW:
        for (Mip = 0; Mip < 16; Mip++) {  // Possible maximum of 16 mipmaps
            if (BaseCreated) {
                if (Header.HasMips == 0)  // Does not have mipmaps, so we are done.
                    break;
                if (Image->Width == 1 && Image->Height == 1)  // Already at the smallest mipmap (1x1), so we are done.
                    break;
                if (Header.MipOffsets[Mip] == 0 || Header.MipLengths == 0)  // No more mipmaps in the file.
                    break;
            }

            switch (Header.AlphaBits)
            {
            case 0:
                if (!BaseCreated) {  // Have not created the base image yet, so use ilTexImage.
                    if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
                        return IL_FALSE;
                    Image = iCurImage;
                    BaseCreated = IL_TRUE;

                    Image->Pal.Palette = (ILubyte*)ialloc(256 * 4);  // 256 entries of ARGB8888 values (1024).
                    if (Image->Pal.Palette == NULL)
                        return IL_FALSE;
                    Image->Pal.PalSize = 1024;
                    Image->Pal.PalType = IL_PAL_BGRA32;  //@TODO: Find out if this is really BGRA data.
                    if (iread(Image->Pal.Palette, 1, 1024) != 1024)  // Read in the palette.
                        return IL_FALSE;
                }
                else {
                    Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL);
                    if (Image->Mipmaps == NULL)
                        return IL_FALSE;

                    // Copy the palette from the first image before we change our Image pointer.
                    iCopyPalette(&Image->Mipmaps->Pal, &Image->Pal);
                    // Move to the next mipmap in the linked list.
                    Image = Image->Mipmaps;
                }
                // The origin should be in the upper left.
                Image->Origin = IL_ORIGIN_UPPER_LEFT;

                // These two should be the same (tells us how much data is in the file for this mipmap level).
                if (Header.MipLengths[Mip] != Image->SizeOfData) {
                    ilSetError(IL_INVALID_FILE_HEADER);
                    return IL_FALSE;
                }
                // Finally read in the image data.
                iseek(Header.MipOffsets[Mip], IL_SEEK_SET);
                if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData)
                    return IL_FALSE;
                break;

            case 1:
                if (!BaseCreated) {  // Have not created the base image yet, so use ilTexImage.
                    if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL))
                        return IL_FALSE;
                    Image = iCurImage;
                    BaseCreated = IL_TRUE;

                    Palette = (ILubyte*)ialloc(256 * 4);
                    if (Palette == NULL)
                        return IL_FALSE;

                    // Read in the palette.
                    if (iread(Palette, 1, 1024) != 1024) {
                        ifree(Palette);
                        return IL_FALSE;
                    }

                    // We only allocate this once and reuse this buffer with every mipmap (since successive ones are smaller).
                    DataAndAlpha = (ILubyte*)ialloc(Image->Width * Image->Height);
                    if (DataAndAlpha == NULL) {
                        ifree(DataAndAlpha);
                        ifree(Palette);
                        return IL_FALSE;
                    }
                }
                else {
                    Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL);
                    if (Image->Mipmaps == NULL)
                        return IL_FALSE;

                    // Move to the next mipmap in the linked list.
                    Image = Image->Mipmaps;
                }
                // The origin should be in the upper left.
                Image->Origin = IL_ORIGIN_UPPER_LEFT;

                // Determine the size of the alpha data following the color indices.
                AlphaSize = Image->Width * Image->Height / 8;
                if (AlphaSize == 0)
                    AlphaSize = 1;  // Should never be 0.
                // These two should be the same (tells us how much data is in the file for this mipmap level).
                if (Header.MipLengths[Mip] != Image->SizeOfData / 4 + AlphaSize) {
                    ilSetError(IL_INVALID_FILE_HEADER);
                    return IL_FALSE;
                }

                // Seek to the data and read it.
                iseek(Header.MipOffsets[Mip], IL_SEEK_SET);
                if (iread(DataAndAlpha, Image->Width * Image->Height, 1) != 1) {
                    ifree(DataAndAlpha);
                    ifree(Palette);
                    return IL_FALSE;
                }

                // Convert the color-indexed data to BGRX.
                for (j = 0; j < Image->Width * Image->Height; j++) {
                    Image->Data[j*4]   = Palette[DataAndAlpha[j]*4];
                    Image->Data[j*4+1] = Palette[DataAndAlpha[j]*4+1];
                    Image->Data[j*4+2] = Palette[DataAndAlpha[j]*4+2];
                }

                // Read in the alpha list.
                if (iread(DataAndAlpha, AlphaSize, 1) != 1) {
                    ifree(DataAndAlpha);
                    ifree(Palette);
                    return IL_FALSE;
                }

                AlphaMask = 0x01;  // Lowest bit
                AlphaOff = 0;
                // The really strange thing about this alpha data is that it is upside-down when compared to the
                //   regular color-indexed data, so we have to flip it.
                for (y = Image->Height - 1; y >= 0; y--) {
                    for (x = 0; x < Image->Width; x++) {
                        if (AlphaMask == 0) {  // Shifting it past the highest bit makes it 0, since we only have 1 byte.
                            AlphaOff++;        // Move along the alpha buffer.
                            AlphaMask = 0x01;  // Reset the alpha mask.
                        }
                        // This is just 1-bit alpha, so it is either on or off.
                        Image->Data[Image->Bps * y + x * 4 + 3] = DataAndAlpha[AlphaOff] & AlphaMask ? 0xFF : 0x00;
                        AlphaMask <<= 1;
                    }
                }

                break;

            default:
                //@TODO: Accept any other alpha values?
                ilSetError(IL_INVALID_FILE_HEADER);
                return IL_FALSE;
            }
        }

        // Done, so we can finally free these two.
        ifree(DataAndAlpha);
        ifree(Palette);

        break;

    case BLP_DXTC:
        for (Mip = 0; Mip < 16; Mip++) {  // Possible maximum of 16 mipmaps
            //@TODO: Other formats
            //if (Header.AlphaBits == 0)
            //	if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
            //	return IL_FALSE;
            if (!BaseCreated) {  // Have not created the base image yet, so use ilTexImage.
                if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL))
                    return IL_FALSE;
                Image = iCurImage;
                BaseCreated = IL_TRUE;
            }
            else {
                if (Header.HasMips == 0)  // Does not have mipmaps, so we are done.
                    break;
                if (Image->Width == 1 && Image->Height == 1)  // Already at the smallest mipmap (1x1), so we are done.
                    break;
                if (Header.MipOffsets[Mip] == 0 || Header.MipLengths[Mip] == 0)  // No more mipmaps in the file.
                    break;

                //@TODO: Other formats
                // ilNewImageFull automatically changes widths and heights of 0 to 1, so we do not have to worry about it.
                Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
                if (Image->Mipmaps == NULL)
                    return IL_FALSE;
                Image = Image->Mipmaps;
            }
            // The origin should be in the upper left.
            Image->Origin = IL_ORIGIN_UPPER_LEFT;

            //@TODO: Only do the allocation once.
            CompData = (ILubyte*)ialloc(Header.MipLengths[Mip]);
            if (CompData == NULL)
                return IL_FALSE;

            // Read in the compressed mipmap data.
            iseek(Header.MipOffsets[Mip], IL_SEEK_SET);
            if (iread(CompData, 1, Header.MipLengths[Mip]) != Header.MipLengths[Mip]) {
                ifree(CompData);
                return IL_FALSE;
            }

            switch (Header.AlphaBits)
            {
            case 0:  // DXT1 without alpha
            case 1:  // DXT1 with alpha
                // Check to make sure that the MipLength reported is the size needed, so that
                //  DecompressDXT1 does not crash.
                CompSize = ((Image->Width + 3) / 4) * ((Image->Height + 3) / 4) * 8;
                if (CompSize != Header.MipLengths[Mip]) {
                    ilSetError(IL_INVALID_FILE_HEADER);
                    ifree(CompData);
                    return IL_FALSE;
                }
                if (!DecompressDXT1(Image, CompData)) {
                    ifree(CompData);
                    return IL_FALSE;
                }
                break;

            case 8:
                // Check to make sure that the MipLength reported is the size needed, so that
                //  DecompressDXT3/5 do not crash.
                CompSize = ((Image->Width + 3) / 4) * ((Image->Height + 3) / 4) * 16;
                if (CompSize != Header.MipLengths[Mip]) {
                    ifree(CompData);
                    ilSetError(IL_INVALID_FILE_HEADER);
                    return IL_FALSE;
                }
                switch (Header.AlphaType)
                {
                case 0:  // All three of
                case 1:  //  these refer to
                case 8:  //  DXT3...
                    if (!DecompressDXT3(Image, CompData)) {
                        ifree(CompData);
                        return IL_FALSE;
                    }
                    break;

                case 7:  // DXT5 compression
                    if (!DecompressDXT5(Image, CompData)) {
                        ifree(CompData);
                        return IL_FALSE;
                    }
                    break;

                    //default:  // Should already be checked by iCheckBlp2.
                }
                break;
                //default:  // Should already be checked by iCheckBlp2.
            }
            //@TODO: Save DXTC data.
            ifree(CompData);
        }
        break;
        //default:
    }

    return ilFixImage();

check_blp1:
    iseek(-148, IL_SEEK_CUR);  // Go back the size of the BLP2 header, since we tried reading it.
    return iLoadBlp1();
}
Esempio n. 3
0
// Internal function used to load the ROT.
ILboolean iLoadRotInternal(void)
{
	ILubyte		Form[4], FormName[4];
	ILuint		FormLen, Width, Height, Format, Channels, CompSize;
	ILuint		MipSize, MipLevel, MipWidth, MipHeight;
	ILenum		FormatIL;
	ILimage		*Image;
	ILboolean	BaseCreated = IL_FALSE;
	ILubyte		*CompData = NULL;

	if (iCurImage == NULL) {
		ilSetError(IL_ILLEGAL_OPERATION);
		return IL_FALSE;
	}

	// The first entry in the file must be 'FORM', 0x20 in a big endian integer and then 'HEAD'.
	iread(Form, 1, 4);
	FormLen = GetBigUInt();
	iread(FormName, 1, 4);
	if (strncmp(Form, "FORM", 4) || FormLen != 0x14 || strncmp(FormName, "HEAD", 4)) {
		ilSetError(IL_INVALID_FILE_HEADER);
		return IL_FALSE;
	}

	// Next follows the width, height and format in the header.
	Width = GetLittleUInt();
	Height = GetLittleUInt();
	Format = GetLittleUInt();

	//@TODO: More formats.
	switch (Format)
	{
		case ROT_RGBA32:  // 32-bit RGBA format
			Channels = 4;
			FormatIL = IL_RGBA;
			break;

		case ROT_DXT1:  // DXT1 (no alpha)
			Channels = 4;
			FormatIL = IL_RGBA;
			break;

		case ROT_DXT3:  // DXT3
		case ROT_DXT5:  // DXT5
			Channels = 4;
			FormatIL = IL_RGBA;
			// Allocates the maximum needed (the first width/height given in the file).
			CompSize = ((Width + 3) / 4) * ((Height + 3) / 4) * 16;
			CompData = ialloc(CompSize);
			if (CompData == NULL)
				return IL_FALSE;
			break;

		default:
			ilSetError(IL_INVALID_FILE_HEADER);
			return IL_FALSE;
	}

	if (Width == 0 || Height == 0) {
		ilSetError(IL_INVALID_FILE_HEADER);
		return IL_FALSE;
	}

	//@TODO: Find out what this is.
	GetLittleUInt();  // Skip this for the moment.  This appears to be the number of channels.

	// Next comes 'FORM', a length and 'MIPS'.
	iread(Form, 1, 4);
	FormLen = GetBigUInt();
	iread(FormName, 1, 4);
	//@TODO: Not sure if the FormLen has to be anything specific here.
	if (strncmp(Form, "FORM", 4) || strncmp(FormName, "MIPS", 4)) {
		ilSetError(IL_INVALID_FILE_HEADER);
		return IL_FALSE;
	}

	//@TODO: Can these mipmap levels be in any order?  Some things may be easier if the answer is no.
	Image = iCurImage;
	do {
		// Then we have 'FORM' again.
		iread(Form, 1, 4);
		// This is the size of the mipmap data.
		MipSize = GetBigUInt();
		iread(FormName, 1, 4);
		if (strncmp(Form, "FORM", 4)) {
			if (!BaseCreated) {  // Our file is malformed.
				ilSetError(IL_INVALID_FILE_HEADER);
				return IL_FALSE;
			}
			// We have reached the end of the mipmap data.
			break;
		}
		if (strncmp(FormName, "MLVL", 4)) {
			ilSetError(IL_INVALID_FILE_HEADER);
			return IL_FALSE;
		}

		// Next is the mipmap attributes (level number, width, height and length)
		MipLevel = GetLittleUInt();
		MipWidth = GetLittleUInt();
		MipHeight = GetLittleUInt();
		MipSize = GetLittleUInt();  // This is the same as the previous size listed -20 (for attributes).

		// Lower level mipmaps cannot be larger than the main image.
		if (MipWidth > Width || MipHeight > Height || MipSize > CompSize) {
			ilSetError(IL_INVALID_FILE_HEADER);
			return IL_FALSE;
		}

		// Just create our images here.
		if (!BaseCreated) {
			if (!ilTexImage(MipWidth, MipHeight, 1, Channels, FormatIL, IL_UNSIGNED_BYTE, NULL))
				return IL_FALSE;
			BaseCreated = IL_TRUE;
		}
		else {
			Image->Mipmaps = ilNewImageFull(MipWidth, MipHeight, 1, Channels, FormatIL, IL_UNSIGNED_BYTE, NULL);
			Image = Image->Mipmaps;
		}

		switch (Format)
		{
			case ROT_RGBA32:  // 32-bit RGBA format
				if (iread(Image->Data, Image->SizeOfData, 1) != 1)
					return IL_FALSE;
				break;

			case ROT_DXT1:
				// Allocates the size of the compressed data.
				CompSize = ((MipWidth + 3) / 4) * ((MipHeight + 3) / 4) * 8;
				if (CompSize != MipSize) {
					ilSetError(IL_INVALID_FILE_HEADER);
					return IL_FALSE;
				}
				CompData = ialloc(CompSize);
				if (CompData == NULL)
					return IL_FALSE;

				// Read in the DXT1 data...
				if (iread(CompData, CompSize, 1) != 1)
					return IL_FALSE;
				// ...and decompress it.
				if (!DecompressDXT1(Image, CompData)) {
					ifree(CompData);
					return IL_FALSE;
				}
				if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
					Image->DxtcSize = CompSize;
					Image->DxtcData = CompData;
					Image->DxtcFormat = IL_DXT1;
					CompData = NULL;
				}
				break;

			case ROT_DXT3:
				// Allocates the size of the compressed data.
				CompSize = ((MipWidth + 3) / 4) * ((MipHeight + 3) / 4) * 16;
				if (CompSize != MipSize) {
					ilSetError(IL_INVALID_FILE_HEADER);
					return IL_FALSE;
				}
				CompData = ialloc(CompSize);
				if (CompData == NULL)
					return IL_FALSE;

				// Read in the DXT3 data...
				if (iread(CompData, MipSize, 1) != 1)
					return IL_FALSE;
				// ...and decompress it.
				if (!DecompressDXT3(Image, CompData)) {
					ifree(CompData);
					return IL_FALSE;
				}
				if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
					Image->DxtcSize = CompSize;
					Image->DxtcData = CompData;
					Image->DxtcFormat = IL_DXT3;
					CompData = NULL;
				}
				break;

			case ROT_DXT5:
				// Allocates the size of the compressed data.
				CompSize = ((MipWidth + 3) / 4) * ((MipHeight + 3) / 4) * 16;
				if (CompSize != MipSize) {
					ilSetError(IL_INVALID_FILE_HEADER);
					return IL_FALSE;
				}
				CompData = ialloc(CompSize);
				if (CompData == NULL)
					return IL_FALSE;

				// Read in the DXT5 data...
				if (iread(CompData, MipSize, 1) != 1)
					return IL_FALSE;
				// ...and decompress it.
				if (!DecompressDXT5(Image, CompData)) {
					ifree(CompData);
					return IL_FALSE;
				}
				// Keeps a copy
				if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
					Image->DxtcSize = CompSize;
					Image->DxtcData = CompData;
					Image->DxtcFormat = IL_DXT5;
					CompData = NULL;
				}
				break;
		}
		ifree(CompData);  // Free it if it was not saved.
	} while (!ieof());  //@TODO: Is there any other condition that should end this?

	return ilFixImage();
}