ILAPI ILpal* ILAPIENTRY iCopyPal()
{
	ILpal *Pal;

	if (iCurImage == NULL || iCurImage->Pal.Palette == NULL ||
		iCurImage->Pal.PalSize == 0 || iCurImage->Pal.PalType == IL_PAL_NONE) {
		ilSetError(IL_ILLEGAL_OPERATION);
		return NULL;
	}

	Pal = (ILpal*)ialloc(sizeof(ILpal));
	if (Pal == NULL) {
		return NULL;
	}
	if (!iCopyPalette(Pal, &iCurImage->Pal)) {
		ifree(Pal);
		return NULL;
	}

	return Pal;
}
Example #2
0
ILboolean GetImages(ILpal *GlobalPal, GIFHEAD *GifHead)
{
	IMAGEDESC	ImageDesc, OldImageDesc;
	GFXCONTROL	Gfx;
	ILboolean	BaseImage = IL_TRUE;
	ILimage		*Image = iCurImage, *TempImage = NULL;
	ILuint		NumImages = 0, i;
	ILint		input;

	Gfx.Used = IL_TRUE;

	while (!ieof()) {
		ILubyte DisposalMethod = 1;

		i = itell();
		if (!SkipExtensions(&Gfx))
			goto error_clean;
		i = itell();
		if (!Gfx.Used)
			DisposalMethod = (Gfx.Packed & 0x1C) >> 2;


		//read image descriptor
		ImageDesc.Separator = igetc();
		if (ImageDesc.Separator != 0x2C) //end of image
			break;
		ImageDesc.OffX = GetLittleUShort();
		ImageDesc.OffY = GetLittleUShort();
		ImageDesc.Width = GetLittleUShort();
		ImageDesc.Height = GetLittleUShort();
		ImageDesc.ImageInfo = igetc();
		if (ieof()) {
			ilGetError();  // Gets rid of the IL_FILE_READ_ERROR that inevitably results.
			break;
		}


		if (!BaseImage) {
			NumImages++;
			Image->Next = ilNewImage(iCurImage->Width, iCurImage->Height, 1, 1, 1);
			if (Image->Next == NULL)
				goto error_clean;

			//20040612: DisposalMethod controls how the new images data is to be combined
			//with the old image. 0 means that it doesn't matter how they are combined,
			//1 means keep the old image, 2 means set to background color, 3 is
			//load the image that was in place before the current (this is not implemented
			//here! (TODO?))
			if (DisposalMethod == 2 || DisposalMethod == 3)
				//Note that this is actually wrong, too: If the image has a local
				//color table, we should really search for the best fit of the
				//background color table and use that index (?). Furthermore,
				//we should only memset the part of the image that is not read
				//later (if we are sure that no parts of the read image are transparent).
				if (!Gfx.Used && Gfx.Packed & 0x1)
					memset(Image->Next->Data, Gfx.Transparent, Image->SizeOfData);
				else
					memset(Image->Next->Data, GifHead->Background, Image->SizeOfData);
			else if (DisposalMethod == 1 || DisposalMethod == 0)
				memcpy(Image->Next->Data, Image->Data, Image->SizeOfData);

			//Interlacing has to be removed after the image was copied (line above)
			if (OldImageDesc.ImageInfo & (1 << 6)) {  // Image is interlaced.
				if (!RemoveInterlace(Image))
					goto error_clean;
			}


			Image = Image->Next;
			Image->Format = IL_COLOUR_INDEX;
			Image->Origin = IL_ORIGIN_UPPER_LEFT;
		}
		else {
			BaseImage = IL_FALSE;
			if (!Gfx.Used && Gfx.Packed & 0x1)
				memset(Image->Data, Gfx.Transparent, Image->SizeOfData);
			else
				memset(Image->Data, GifHead->Background, Image->SizeOfData);
			//memset(Image->Data, GifHead->Background, Image->SizeOfData);
		}

		Image->OffX = ImageDesc.OffX;
		Image->OffY = ImageDesc.OffY;


		// Check to see if the image has its own palette.
		if (ImageDesc.ImageInfo & (1 << 7)) {
			if (!iGetPalette(ImageDesc.ImageInfo, &Image->Pal)) {
				goto error_clean;
			}
		}
		else {
			if (!iCopyPalette(&Image->Pal, GlobalPal)) {
				goto error_clean;
			}
		}


		if (!GifGetData(Image->Data + ImageDesc.OffX + ImageDesc.OffY*Image->Width, Image->SizeOfData,
				ImageDesc.Width, ImageDesc.Height, Image->Width, &Gfx)) {
			ilSetError(IL_ILLEGAL_FILE_VALUE);
			goto error_clean;
		}

		// See if there was a valid graphics control extension.
		if (!Gfx.Used) {
			Gfx.Used = IL_TRUE;
			Image->Duration = Gfx.Delay * 10;  // We want it in milliseconds.

			// See if a transparent colour is defined.
			if (Gfx.Packed & 1) {
				if (!ConvertTransparent(Image, Gfx.Transparent)) {
					goto error_clean;
				}
			}
		}

		i = itell();

		// Terminates each block.
		if((input = igetc()) == IL_EOF)
			goto error_clean;

		if (input != 0x00)
			iseek(-1, IL_SEEK_CUR);
		//	break;

		OldImageDesc = ImageDesc;
	}

	//Deinterlace last image
	if (OldImageDesc.ImageInfo & (1 << 6)) {  // Image is interlaced.
		if (!RemoveInterlace(Image))
			goto error_clean;
	}


	iCurImage->NumNext = NumImages;
	if (BaseImage)  // Was not able to load any images in...
		return IL_FALSE;

	return IL_TRUE;

error_clean:
	Image = iCurImage->Next;
	while (Image) {
		TempImage = Image;
		Image = Image->Next;
		ilCloseImage(TempImage);
	}
	
	return IL_FALSE;
}
Example #3
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();
}