//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2008 by Denton Woods
// Last modified: 01/08/2007
//
// Filename: src-IL/src/il_dds.c
//
// Description: Reads from a DirectDraw Surface (.dds) file.
//
//-----------------------------------------------------------------------------


//
//
// Note:  Almost all this code is from nVidia's DDS-loading example at
//	http://www.nvidia.com/view.asp?IO=dxtc_decompression_code
//	and from the specs at
//	http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dx8_c/hh/dx8_c/graphics_using_0j03.asp
//	and
//	http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dx8_c/directx_cpp/Graphics/ProgrammersGuide/Appendix/DDSFileFormat/ovwDDSFileFormat.asp
//	However, some not really valid .dds files are also read, for example
//	Volume Textures without the COMPLEX bit set, so the specs aren't taken
//	too strictly while reading.


#include "il_internal.h"
#ifndef IL_NO_DDS
#include "il_dds.h"


// Global variables
static DDSHEAD	Head;			// Image header
static ILubyte	*CompData;		// Compressed data
static ILuint	CompSize;		// Compressed size
static ILuint	CompFormat;		// Compressed format
static ILimage	*Image;
static ILint	Width, Height, Depth;

ILuint CubemapDirections[CUBEMAP_SIDES] = {
	DDS_CUBEMAP_POSITIVEX,
	DDS_CUBEMAP_NEGATIVEX,
	DDS_CUBEMAP_POSITIVEY,
	DDS_CUBEMAP_NEGATIVEY,
	DDS_CUBEMAP_POSITIVEZ,
	DDS_CUBEMAP_NEGATIVEZ
};


//! Checks if the file specified in FileName is a valid .dds file.
ILboolean ilIsValidDds(ILconst_string FileName)
{
	ILHANDLE	DdsFile;
	ILboolean	bDds = IL_FALSE;

	if (!iCheckExtension(FileName, IL_TEXT("dds"))) {
		ilSetError(IL_INVALID_EXTENSION);
		return bDds;
	}

	DdsFile = iopenr(FileName);
	if (DdsFile == NULL) {
		ilSetError(IL_COULD_NOT_OPEN_FILE);
		return bDds;
	}

	bDds = ilIsValidDdsF(DdsFile);
	icloser(DdsFile);

	return bDds;
}


//! Checks if the ILHANDLE contains a valid .dds file at the current position.
ILboolean ilIsValidDdsF(ILHANDLE File)
{
	ILuint		FirstPos;
	ILboolean	bRet;

	iSetInputFile(File);
	FirstPos = itell();
	bRet = iIsValidDds();
	iseek(FirstPos, IL_SEEK_SET);

	return bRet;
}


//! Checks if Lump is a valid .dds lump.
ILboolean ilIsValidDdsL(const ILvoid *Lump, ILuint Size)
{
	iSetInputLump(Lump, Size);
	return iIsValidDds();
}


// Internal function used to get the .dds header from the current file.
ILboolean iGetDdsHead(DDSHEAD *Header)
{

	ILint i;



	iread(&Header->Signature, 1, 4);
	Header->Size1 = GetLittleUInt();
	Header->Flags1 = GetLittleUInt();
	Header->Height = GetLittleUInt();
	Header->Width = GetLittleUInt();
	Header->LinearSize = GetLittleUInt();
	Header->Depth = GetLittleUInt();
	Header->MipMapCount = GetLittleUInt();
	Header->AlphaBitDepth = GetLittleUInt();



	for (i = 0; i < 10; ++i)

		Header->NotUsed[i] = GetLittleUInt();


	Header->Size2 = GetLittleUInt();
	Header->Flags2 = GetLittleUInt();
	Header->FourCC = GetLittleUInt();
	Header->RGBBitCount = GetLittleUInt();
	Header->RBitMask = GetLittleUInt();
	Header->GBitMask = GetLittleUInt();
	Header->BBitMask = GetLittleUInt();
	Header->RGBAlphaBitMask = GetLittleUInt();
	Header->ddsCaps1 = GetLittleUInt();
	Header->ddsCaps2 = GetLittleUInt();
	Header->ddsCaps3 = GetLittleUInt();
	Header->ddsCaps4 = GetLittleUInt();
	Header->TextureStage = GetLittleUInt();

	if (Head.Depth == 0)
		Head.Depth = 1;

	return IL_TRUE;
}


// Internal function to get the header and check it.
ILboolean iIsValidDds()
{
	ILboolean	IsValid;
	DDSHEAD		Head;

	iGetDdsHead(&Head);
	iseek(-(ILint)sizeof(DDSHEAD), IL_SEEK_CUR);  // Go ahead and restore to previous state

	IsValid = iCheckDds(&Head);

	return IsValid;
}


// Internal function used to check if the HEADER is a valid .dds header.
ILboolean iCheckDds(DDSHEAD *Head)
{
	if (strncmp((const char*)Head->Signature, "DDS ", 4))
		return IL_FALSE;
	//note that if Size1 is "DDS " this is not a valid dds file according
	//to the file spec. Some broken tool out there seems to produce files
	//with this value in the size field, so we support reading them...
	if (Head->Size1 != 124 && Head->Size1 != IL_MAKEFOURCC('D', 'D', 'S', ' '))
		return IL_FALSE;
	if (Head->Size2 != 32)
		return IL_FALSE;
	if (Head->Width == 0 || Head->Height == 0)
		return IL_FALSE;
	return IL_TRUE;
}


//! Reads a .dds file
ILboolean ilLoadDds(ILconst_string FileName)
{
	ILHANDLE	DdsFile;
	ILboolean	bDds = IL_FALSE;

	DdsFile = iopenr(FileName);
	if (DdsFile == NULL) {
		ilSetError(IL_COULD_NOT_OPEN_FILE);
		return bDds;
	}

	bDds = ilLoadDdsF(DdsFile);
	icloser(DdsFile);

	return bDds;
}


//! Reads an already-opened .dds file
ILboolean ilLoadDdsF(ILHANDLE File)
{
	ILuint		FirstPos;
	ILboolean	bRet;

	iSetInputFile(File);
	FirstPos = itell();
	bRet = iLoadDdsInternal();
	iseek(FirstPos, IL_SEEK_SET);

	return bRet;
}


//! Reads from a memory "lump" that contains a .dds
ILboolean ilLoadDdsL(const ILvoid *Lump, ILuint Size)
{
	iSetInputLump(Lump, Size);
	return iLoadDdsInternal();
}


ILubyte iCompFormatToBpp(ILenum Format)

{

	//non-compressed (= non-FOURCC) codes

	if (Format == PF_LUMINANCE || Format == PF_LUMINANCE_ALPHA || Format == PF_ARGB)

		return Head.RGBBitCount/8;



	//fourcc formats

	else if (Format == PF_RGB || Format == PF_3DC || Format == PF_RXGB)

		return 3;

	else if (Format == PF_ATI1N)

		return 1;

	else if (Format == PF_R16F)

		return 2;

	else if (Format == PF_A16B16G16R16 || Format == PF_A16B16G16R16F

		|| Format == PF_G32R32F)

		return 8;

	else if (Format == PF_A32B32G32R32F)

		return 16;

	else //if (Format == PF_G16R16F || Format == PF_R32F || dxt)

		return 4;

}



ILubyte iCompFormatToBpc(ILenum Format)

{

	if (Format == PF_R16F || Format == PF_G16R16F || Format == PF_A16B16G16R16F)

		//DevIL has no internal half type, so these formats are converted to 32 bits

		return 4;

	else if (Format == PF_R32F || Format == PF_G32R32F || Format == PF_A32B32G32R32F)

		return 4;

	else if(Format == PF_A16B16G16R16)

		return 2;

	else

		return 1;

}



ILubyte iCompFormatToChannelCount(ILenum Format)

{

	if (Format == PF_RGB || Format == PF_3DC || Format == PF_RXGB)

		return 3;

	else if (Format == PF_LUMINANCE || Format == PF_R16F || Format == PF_R32F || Format == PF_ATI1N)

		return 1;

	else if (Format == PF_LUMINANCE_ALPHA || Format == PF_G16R16F || Format == PF_G32R32F)

		return 2;

	else //if(Format == PF_ARGB || dxt)

		return 4;

}

ILboolean iLoadDdsCubemapInternal()
{
	ILuint	i;
	ILubyte	Bpp, Channels, Bpc;
	ILimage *startImage;

	CompData = NULL;

	Bpp = iCompFormatToBpp(CompFormat);

	Channels = iCompFormatToChannelCount(CompFormat);

	Bpc = iCompFormatToBpc(CompFormat);

	if(CompFormat == PF_LUMINANCE && Head.RGBBitCount == 16 && Head.RBitMask == 0xFFFF) { //HACK

		Bpc = 2; Bpp = 2;

	}


	startImage = Image;
	// run through cube map possibilities
	for (i = 0; i < CUBEMAP_SIDES; i++) {
		// reset each time
		Width = Head.Width;
		Height = Head.Height;
		Depth = Head.Depth;
		if (Head.ddsCaps2 & CubemapDirections[i]) {
			if (i != 0) {
				Image->Next = ilNewImage(Width, Height, Depth, Channels, Bpc);
				if (Image->Next == NULL)
					return IL_FALSE;

				Image = Image->Next;

				if (CompFormat == PF_R16F
					|| CompFormat == PF_G16R16F
					|| CompFormat == PF_A16B16G16R16F
					|| CompFormat == PF_R32F
					|| CompFormat == PF_G32R32F
					|| CompFormat == PF_A32B32G32R32F) {
					//DevIL's format autodetection doesn't work for
					//float images...correct this
					Image->Type = IL_FLOAT;
					Image->Bpp = Channels;
				}

				ilBindImage(ilGetCurName()); // Set to parent image first.
				ilActiveImage(i); //now Image == iCurImage...globals SUCK, fix this!!!
			}

			if (!ReadData())
				return IL_FALSE;

			if (!AllocImage()) {
				if (CompData) {
					ifree(CompData);
					CompData = NULL;
				}
				return IL_FALSE;
			}

			Image->CubeFlags = CubemapDirections[i];

			if (!Decompress()) {
				if (CompData) {
					ifree(CompData);
					CompData = NULL;
				}
				return IL_FALSE;
			}

			if (!ReadMipmaps()) {
				if (CompData) {
					ifree(CompData);
					CompData = NULL;
				}
				return IL_FALSE;
			}
		}
	}

	if (CompData) {
		ifree(CompData);
		CompData = NULL;
	}

	ilBindImage(ilGetCurName());  // Set to parent image first.
	return ilFixImage();
}


ILboolean iLoadDdsInternal()
{
	ILuint BlockSize = 0;

	CompData = NULL;
	Image = NULL;

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

	if (!iGetDdsHead(&Head)) {
		ilSetError(IL_INVALID_FILE_HEADER);
		return IL_FALSE;
	}
	if(!iCheckDds(&Head)) {
		ilSetError(IL_INVALID_FILE_HEADER);
		return IL_FALSE;
	}

	BlockSize = DecodePixelFormat();
	if (CompFormat == PF_UNKNOWN) {
		ilSetError(IL_INVALID_FILE_HEADER);
		return IL_FALSE;
	}

	// Microsoft bug, they're not following their own documentation.
	if (!(Head.Flags1 & (DDS_LINEARSIZE | DDS_PITCH))
		|| Head.LinearSize == 0) {
		Head.Flags1 |= DDS_LINEARSIZE;
		Head.LinearSize = BlockSize;
	}

	Image = iCurImage;
	if (Head.ddsCaps1 & DDS_COMPLEX) {
		if (Head.ddsCaps2 & DDS_CUBEMAP) {
			if (!iLoadDdsCubemapInternal())
				return IL_FALSE;
			return IL_TRUE;
		}
	}

	Width = Head.Width;
	Height = Head.Height;
	Depth = Head.Depth;
	AdjustVolumeTexture(&Head);

	if (!ReadData())
		return IL_FALSE;
	if (!AllocImage()) {
		if (CompData) {
			ifree(CompData);
			CompData = NULL;
		}
		return IL_FALSE;
	}
	if (!Decompress()) {
		if (CompData) {
			ifree(CompData);
			CompData = NULL;
		}
		return IL_FALSE;
	}

	if (!ReadMipmaps()) {
		if (CompData) {
			ifree(CompData);
			CompData = NULL;
		}
		return IL_FALSE;
	}

	if (CompData) {
		ifree(CompData);
		CompData = NULL;
	}

	ilBindImage(ilGetCurName());  // Set to parent image first.
	return ilFixImage();
}


ILuint DecodePixelFormat()
{
	ILuint BlockSize;

	if (Head.Flags2 & DDS_FOURCC) {
		BlockSize = ((Head.Width + 3)/4) * ((Head.Height + 3)/4) * Head.Depth;
		switch (Head.FourCC)
		{
			case IL_MAKEFOURCC('D','X','T','1'):
				CompFormat = PF_DXT1;
				BlockSize *= 8;
				break;

			case IL_MAKEFOURCC('D','X','T','2'):
				CompFormat = PF_DXT2;
				BlockSize *= 16;
				break;

			case IL_MAKEFOURCC('D','X','T','3'):
				CompFormat = PF_DXT3;
				BlockSize *= 16;
				break;

			case IL_MAKEFOURCC('D','X','T','4'):
				CompFormat = PF_DXT4;
				BlockSize *= 16;
				break;

			case IL_MAKEFOURCC('D','X','T','5'):
				CompFormat = PF_DXT5;
				BlockSize *= 16;
				break;



			case IL_MAKEFOURCC('A', 'T', 'I', '1'):

				CompFormat = PF_ATI1N;

				BlockSize *= 8;

				break;

			case IL_MAKEFOURCC('A', 'T', 'I', '2'):
				CompFormat = PF_3DC;
				BlockSize *= 16;
				break;

			case IL_MAKEFOURCC('R', 'X', 'G', 'B'):
				CompFormat = PF_RXGB;
				BlockSize *= 16;
				break;

			case IL_MAKEFOURCC('$', '\0', '\0', '\0'):
				CompFormat = PF_A16B16G16R16;
				BlockSize = Head.Width * Head.Height * Head.Depth * 8;
				break;

			case IL_MAKEFOURCC('o', '\0', '\0', '\0'):
				CompFormat = PF_R16F;
				BlockSize = Head.Width * Head.Height * Head.Depth * 2;
				break;

			case IL_MAKEFOURCC('p', '\0', '\0', '\0'):
				CompFormat = PF_G16R16F;
				BlockSize = Head.Width * Head.Height * Head.Depth * 4;
				break;

			case IL_MAKEFOURCC('q', '\0', '\0', '\0'):
				CompFormat = PF_A16B16G16R16F;
				BlockSize = Head.Width * Head.Height * Head.Depth * 8;
				break;

			case IL_MAKEFOURCC('r', '\0', '\0', '\0'):
				CompFormat = PF_R32F;
				BlockSize = Head.Width * Head.Height * Head.Depth * 4;
				break;

			case IL_MAKEFOURCC('s', '\0', '\0', '\0'):
				CompFormat = PF_G32R32F;
				BlockSize = Head.Width * Head.Height * Head.Depth * 8;
				break;

			case IL_MAKEFOURCC('t', '\0', '\0', '\0'):
				CompFormat = PF_A32B32G32R32F;
				BlockSize = Head.Width * Head.Height * Head.Depth * 16;
				break;

			default:
				CompFormat = PF_UNKNOWN;
				BlockSize *= 16;
				break;
		}
	} else {
		// This dds texture isn't compressed so write out ARGB or luminance format
		if (Head.Flags2 & DDS_LUMINANCE) {
			if (Head.Flags2 & DDS_ALPHAPIXELS) {
				CompFormat = PF_LUMINANCE_ALPHA;
			} else {
				CompFormat = PF_LUMINANCE;
			}
		}
		else {
			if (Head.Flags2 & DDS_ALPHAPIXELS) {
				CompFormat = PF_ARGB;
			} else {
				CompFormat = PF_RGB;
			}
		}
		BlockSize = (Head.Width * Head.Height * Head.Depth * (Head.RGBBitCount >> 3));
	}

	return BlockSize;
}


// The few volume textures that I have don't have consistent LinearSize
//	entries, even though the DDS_LINEARSIZE flag is set.
ILvoid AdjustVolumeTexture(DDSHEAD *Head)
{
	if (Head->Depth <= 1)
		return;

	// All volume textures I've seem so far didn't have the DDS_COMPLEX flag set,
	// even though this is normally required. But because noone does set it,
	// also read images without it (TODO: check file size for 3d texture?)
	if (/*!(Head->ddsCaps1 & DDS_COMPLEX) ||*/ !(Head->ddsCaps2 & DDS_VOLUME)) {
		Head->Depth = 1;
		Depth = 1;
	}

	switch (CompFormat)
	{
		case PF_ARGB:
		case PF_RGB:
		case PF_LUMINANCE:
		case PF_LUMINANCE_ALPHA:
			//don't use the iCompFormatToBpp() function because this way
			//argb images with only 8 bits (eg. a1r2g3b2) work as well
			Head->LinearSize = IL_MAX(1,Head->Width) * IL_MAX(1,Head->Height) *
				(Head->RGBBitCount / 8);
			break;
	
		case PF_DXT1:

		case PF_ATI1N:
			Head->LinearSize = ((Head->Width+3)/4) * ((Head->Height+3)/4) * 8;
			break;

		case PF_DXT2:
		case PF_DXT3:
		case PF_DXT4:
		case PF_DXT5:
		case PF_3DC:
		case PF_RXGB:
			Head->LinearSize = ((Head->Width+3)/4) * ((Head->Height+3)/4) * 16;
			break;

		case PF_A16B16G16R16:
		case PF_R16F:
		case PF_G16R16F:
		case PF_A16B16G16R16F:
		case PF_R32F:
		case PF_G32R32F:
		case PF_A32B32G32R32F:
			Head->LinearSize = IL_MAX(1,Head->Width) * IL_MAX(1,Head->Height) *
				iCompFormatToBpp(CompFormat);
			break;
	}

	Head->Flags1 |= DDS_LINEARSIZE;
	Head->LinearSize *= Head->Depth;

	return;
}


// Reads the compressed data
ILboolean ReadData()
{
	ILuint	Bps;
	ILint	y, z;
	ILubyte	*Temp;

	if (CompData) {
		ifree(CompData);
		CompData = NULL;
	}

	if (Head.Flags1 & DDS_LINEARSIZE) {
		//Head.LinearSize = Head.LinearSize * Depth;

		CompData = (ILubyte*)ialloc(Head.LinearSize);
		if (CompData == NULL) {
			return IL_FALSE;
		}

		if (iread(CompData, 1, Head.LinearSize) != (ILuint)Head.LinearSize) {
			ifree(CompData);
			CompData = NULL;
			return IL_FALSE;
		}
	}
	else {
		Bps = Width * Head.RGBBitCount / 8;
		CompSize = Bps * Height * Depth;

		CompData = (ILubyte*)ialloc(CompSize);
		if (CompData == NULL) {
			return IL_FALSE;
		}

		Temp = CompData;
		for (z = 0; z < Depth; z++) {
			for (y = 0; y < Height; y++) {
				if (iread(Temp, 1, Bps) != Bps) {
					ifree(CompData);
					CompData = NULL;
					return IL_FALSE;
				}
				Temp += Bps;
			}
		}
	}

	return IL_TRUE;
}


ILboolean AllocImage()
{
	ILubyte channels = 4;
	ILenum format = IL_RGBA;

	switch (CompFormat)
	{
		case PF_RGB:
			if (!ilTexImage(Width, Height, Depth, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
				return IL_FALSE;
			break;
		case PF_ARGB:
			if (!ilTexImage(Width, Height, Depth, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL))
				return IL_FALSE;
			break;

		case PF_LUMINANCE:

			if(Head.RGBBitCount == 16 && Head.RBitMask == 0xFFFF) { //HACK

				if (!ilTexImage(Width, Height, Depth, 1, IL_LUMINANCE, IL_UNSIGNED_SHORT, NULL))

					return IL_FALSE;

			}

			else

				if (!ilTexImage(Width, Height, Depth, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL))

					return IL_FALSE;

			break;

		case PF_LUMINANCE_ALPHA:

			if (!ilTexImage(Width, Height, Depth, 2, IL_LUMINANCE_ALPHA, IL_UNSIGNED_BYTE, NULL))

				return IL_FALSE;

			break;



		case PF_ATI1N:

			//right now there's no OpenGL api to use the compressed 3dc data, so

			//throw it away (I don't know how DirectX works, though)?

			if (!ilTexImage(Width, Height, Depth, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL))

				return IL_FALSE;

			break;



		case PF_3DC:

			//right now there's no OpenGL api to use the compressed 3dc data, so

			//throw it away (I don't know how DirectX works, though)?

			if (!ilTexImage(Width, Height, Depth, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))

				return IL_FALSE;

			break;



		case PF_A16B16G16R16:

			if (!ilTexImage(Width, Height, Depth, iCompFormatToChannelCount(CompFormat),

				ilGetFormatBpp(iCompFormatToChannelCount(CompFormat)), IL_UNSIGNED_SHORT, NULL))

				return IL_FALSE;

			break;



		case PF_R16F:

		case PF_G16R16F:

		case PF_A16B16G16R16F:

		case PF_R32F:

		case PF_G32R32F:

		case PF_A32B32G32R32F:

			if (!ilTexImage(Width, Height, Depth, iCompFormatToChannelCount(CompFormat),

				ilGetFormatBpp(iCompFormatToChannelCount(CompFormat)), IL_FLOAT, NULL))

				return IL_FALSE;

			break;


		default:

			if (CompFormat == PF_RXGB) {

				channels = 3; //normal map

				format = IL_RGB;

			}


			if (!ilTexImage(Width, Height, Depth, channels, format, IL_UNSIGNED_BYTE, NULL))
				return IL_FALSE;
			if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE && CompData) {
				iCurImage->DxtcData = (ILubyte*)ialloc(Head.LinearSize);
				if (iCurImage->DxtcData == NULL)
					return IL_FALSE;
				iCurImage->DxtcFormat = CompFormat - PF_DXT1 + IL_DXT1;
				iCurImage->DxtcSize = Head.LinearSize;
				memcpy(iCurImage->DxtcData, CompData, iCurImage->DxtcSize);
			}
			break;
	}

	Image->Origin = IL_ORIGIN_UPPER_LEFT;
	
	return IL_TRUE;
}


/*
 * Assumes that the global variable CompFormat stores the format of the
 * global pointer CompData (that's the pointer to the compressed data).
 * Decompresses this data into Image->Data, returns if it was successful.
 * It also uses the globals Width and Height.
 *
 * Assumes that iCurImage has valid Width, Height, Depth, Data, SizeOfData,
 * Bpp, Bpc, Bps, SizeOfPlane, Format and Type fields. It is more or
 * less assumed that the image has u8 rgba data (perhaps not for float
 * images...)
 *
 *
 * TODO: don't use globals, clean this function (and this file) up
 */
ILboolean Decompress()
{
	switch (CompFormat)
	{
		case PF_ARGB:
		case PF_RGB:
		case PF_LUMINANCE:
		case PF_LUMINANCE_ALPHA:
			return DecompressARGB();

		case PF_DXT1:
			return DecompressDXT1();

		case PF_DXT2:
			return DecompressDXT2();

		case PF_DXT3:
			return DecompressDXT3();

		case PF_DXT4:
			return DecompressDXT4();

		case PF_DXT5:
			return DecompressDXT5();


		case PF_ATI1N:

			return DecompressAti1n();


		case PF_3DC:
			return Decompress3Dc();

		case PF_RXGB:
			return DecompressRXGB();

		case PF_A16B16G16R16:
			memcpy(Image->Data, CompData, Image->SizeOfData);
			return IL_TRUE;


		case PF_R16F:
		case PF_G16R16F:
		case PF_A16B16G16R16F:
		case PF_R32F:
		case PF_G32R32F:
		case PF_A32B32G32R32F:
			return DecompressFloat();


		case PF_UNKNOWN:
			return IL_FALSE;
	}

	return IL_FALSE;
}


ILboolean ReadMipmaps()
{
	ILuint	i, CompFactor=0;
	ILubyte	Bpp, Channels, Bpc;
	ILimage	*StartImage, *TempImage;
	ILuint	LastLinear;
	ILuint	minW, minH;

	ILboolean isCompressed = IL_FALSE;


	Bpp = iCompFormatToBpp(CompFormat);

	Channels = iCompFormatToChannelCount(CompFormat);

	Bpc = iCompFormatToBpc(CompFormat);

	if(CompFormat == PF_LUMINANCE && Head.RGBBitCount == 16 && Head.RBitMask == 0xFFFF) { //HACK

		Bpc = 2; Bpp = 2;

	}


	//This doesn't work for images which first mipmap (= the image

	//itself) has width or height < 4
	//if (Head.Flags1 & DDS_LINEARSIZE) {
	//	CompFactor = (Width * Height * Depth * Bpp) / Head.LinearSize;
	//}
	switch(CompFormat)
	{
		case PF_DXT1:
			//This is officially 6, we have 8 here because DXT1 may contain alpha
			CompFactor = 8;
			break;
		case PF_DXT2:
		case PF_DXT3:
		case PF_DXT4:
		case PF_DXT5:
			CompFactor = 4;
			break;
		case PF_RXGB:
		case PF_3DC:
			//This is officially 4 for 3dc, but that's bullshit :) There's no
			//alpha data in 3dc images
			CompFactor = 3;
			break;

		case PF_ATI1N:

			CompFactor = 2;

			break;
		default:
			CompFactor = 1;
	}

	StartImage = Image;

	if (!(Head.Flags1 & DDS_MIPMAPCOUNT) || Head.MipMapCount == 0) {
		//some .dds-files have their mipmap flag set,
		//but a mipmapcount of 0. Because mipMapCount is an uint, 0 - 1 gives
		//overflow - don't let this happen:
		Head.MipMapCount = 1;
	}

	LastLinear = Head.LinearSize;
	for (i = 0; i < Head.MipMapCount - 1; i++) {
		Depth = Depth / 2;
		Width = Width / 2;
		Height = Height / 2;

		if (Depth == 0) 
			Depth = 1;
		if (Width == 0) 
			Width = 1;
		if (Height == 0) 
			Height = 1;

		Image->Next = ilNewImage(Width, Height, Depth, Channels, Bpc);
		if (Image->Next == NULL)
			goto mip_fail;
		Image = Image->Next;
		Image->Origin = IL_ORIGIN_UPPER_LEFT;

		if (Head.Flags1 & DDS_LINEARSIZE) {

			if (CompFormat == PF_R16F

				|| CompFormat == PF_G16R16F

				|| CompFormat == PF_A16B16G16R16F

				|| CompFormat == PF_R32F

				|| CompFormat == PF_G32R32F

				|| CompFormat == PF_A32B32G32R32F) {

				Head.LinearSize = Width * Height * Depth * Bpp;



				//DevIL's format autodetection doesn't work for

				//float images...correct this

				Image->Type = IL_FLOAT;

				Image->Bpp = Channels;

			}

			else if (CompFormat == PF_A16B16G16R16)

				Head.LinearSize = Width * Height * Depth * Bpp;
			else if (CompFormat != PF_RGB && CompFormat != PF_ARGB

				&& CompFormat != PF_LUMINANCE

				&& CompFormat != PF_LUMINANCE_ALPHA) {

				//compressed format
				minW = (((Width+3)/4))*4;
				minH = (((Height+3)/4))*4;
				Head.LinearSize = (minW * minH * Depth * Bpp) / CompFactor;

				isCompressed = IL_TRUE;
			}
			else {
				//don't use Bpp to support argb images with less than 32 bits
				Head.LinearSize = Width * Height * Depth * (Head.RGBBitCount >> 3);
			}
		}
		else {
			Head.LinearSize >>= 1;
		}

		if (!ReadData())
			goto mip_fail;



		if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE && isCompressed == IL_TRUE && CompData) {

			Image->DxtcData = (ILubyte*)ialloc(Head.LinearSize);

			if (Image->DxtcData == NULL)

				return IL_FALSE;

			Image->DxtcFormat = CompFormat - PF_DXT1 + IL_DXT1;

			Image->DxtcSize = Head.LinearSize;

			memcpy(Image->DxtcData, CompData, Image->DxtcSize);

		}


		if (!Decompress())
			goto mip_fail;
	}

	Head.LinearSize = LastLinear;
	StartImage->Mipmaps = StartImage->Next;
	StartImage->Next = NULL;
	Image = StartImage;

	return IL_TRUE;

mip_fail:
	Image = StartImage;
	StartImage = StartImage->Next;
	while (StartImage) {
		TempImage = StartImage;
		StartImage = StartImage->Next;
		ifree(TempImage);
	}

	Image->Next = NULL;
	return IL_FALSE;
}

ILvoid ReadColors(const ILubyte* Data, Color8888* Out)
{
	ILubyte r0, g0, b0, r1, g1, b1;

	b0 = Data[0] & 0x1F;
	g0 = ((Data[0] & 0xE0) >> 5) | ((Data[1] & 0x7) << 3);
	r0 = (Data[1] & 0xF8) >> 3;

	b1 = Data[2] & 0x1F;
	g1 = ((Data[2] & 0xE0) >> 5) | ((Data[3] & 0x7) << 3);
	r1 = (Data[3] & 0xF8) >> 3;

	Out[0].r = r0 << 3;
	Out[0].g = g0 << 2;
	Out[0].b = b0 << 3;

	Out[1].r = r1 << 3;
	Out[1].g = g1 << 2;
	Out[1].b = b1 << 3;
}

ILvoid ReadColor(ILushort Data, Color8888* Out)
{
	ILubyte r, g, b;

	b = Data & 0x1f;
	g = (Data & 0x7E0) >> 5;
	r = (Data & 0xF800) >> 11;

	Out->r = r << 3;
	Out->g = g << 2;
	Out->b = b << 3;
}

ILboolean DecompressDXT1()
{
	int			x, y, z, i, j, k, Select;
	ILubyte		*Temp;
	Color8888	colours[4], *col;
	ILushort	color_0, color_1;
	ILuint		bitmask, Offset;

	if (!CompData)
		return IL_FALSE;

	Temp = CompData;
	colours[0].a = 0xFF;
	colours[1].a = 0xFF;
	colours[2].a = 0xFF;
	//colours[3].a = 0xFF;
	for (z = 0; z < Depth; z++) {
		for (y = 0; y < Height; y += 4) {
			for (x = 0; x < Width; x += 4) {
				color_0 = *((ILushort*)Temp);
				UShort(&color_0);
				color_1 = *((ILushort*)(Temp + 2));
				UShort(&color_1);
				ReadColor(color_0, colours);
				ReadColor(color_1, colours + 1);
				bitmask = ((ILuint*)Temp)[1];
				UInt(&bitmask);
				Temp += 8;

				if (color_0 > color_1) {
					// Four-color block: derive the other two colors.
					// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
					// These 2-bit codes correspond to the 2-bit fields 
					// stored in the 64-bit block.
					colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
					colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
					colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
					//colours[2].a = 0xFF;

					colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
					colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
					colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
					colours[3].a = 0xFF;
				}
				else { 
					// Three-color block: derive the other color.
					// 00 = color_0,  01 = color_1,  10 = color_2,
					// 11 = transparent.
					// These 2-bit codes correspond to the 2-bit fields 
					// stored in the 64-bit block. 
					colours[2].b = (colours[0].b + colours[1].b) / 2;
					colours[2].g = (colours[0].g + colours[1].g) / 2;
					colours[2].r = (colours[0].r + colours[1].r) / 2;
					//colours[2].a = 0xFF;

					colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
					colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
					colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
					colours[3].a = 0x00;
				}

				for (j = 0, k = 0; j < 4; j++) {
					for (i = 0; i < 4; i++, k++) {

						Select = (bitmask & (0x03 << k*2)) >> k*2;
						col = &colours[Select];

						if (((x + i) < Width) && ((y + j) < Height)) {
							Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp;
							Image->Data[Offset + 0] = col->r;
							Image->Data[Offset + 1] = col->g;
							Image->Data[Offset + 2] = col->b;
							Image->Data[Offset + 3] = col->a;
						}
					}
				}
			}
		}
	}

	return IL_TRUE;
}


ILboolean DecompressDXT2()
{
	// Can do color & alpha same as dxt3, but color is pre-multiplied 
	//   so the result will be wrong unless corrected. 
	if (!DecompressDXT3())
		return IL_FALSE;
	CorrectPreMult();

	return IL_TRUE;
}


ILboolean DecompressDXT3()
{
	int			x, y, z, i, j, k, Select;
	ILubyte		*Temp;
	//Color565	*color_0, *color_1;
	Color8888	colours[4], *col;
	ILuint		bitmask, Offset;
	ILushort	word;
	ILubyte *alpha;

	if (!CompData)
		return IL_FALSE;

	Temp = CompData;
	for (z = 0; z < Depth; z++) {
		for (y = 0; y < Height; y += 4) {
			for (x = 0; x < Width; x += 4) {
				alpha = Temp;
				Temp += 8;
				ReadColors(Temp, colours);
				bitmask = ((ILuint*)Temp)[1];
				UInt(&bitmask);
				Temp += 8;

				// Four-color block: derive the other two colors.    
				// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
				// These 2-bit codes correspond to the 2-bit fields 
				// stored in the 64-bit block.
				colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
				colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
				colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
				//colours[2].a = 0xFF;

				colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
				colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
				colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
				//colours[3].a = 0xFF;

				k = 0;
				for (j = 0; j < 4; j++) {
					for (i = 0; i < 4; i++, k++) {

						Select = (bitmask & (0x03 << k*2)) >> k*2;
						col = &colours[Select];

						if (((x + i) < Width) && ((y + j) < Height)) {
							Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp;
							Image->Data[Offset + 0] = col->r;
							Image->Data[Offset + 1] = col->g;
							Image->Data[Offset + 2] = col->b;
						}
					}
				}

				for (j = 0; j < 4; j++) {
					word = alpha[2*j] + 256*alpha[2*j+1];
					for (i = 0; i < 4; i++) {
						if (((x + i) < Width) && ((y + j) < Height)) {
							Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp + 3;
							Image->Data[Offset] = word & 0x0F;
							Image->Data[Offset] = Image->Data[Offset] | (Image->Data[Offset] << 4);
						}
						word >>= 4;
					}
				}

			}
		}
	}

	return IL_TRUE;
}


ILboolean DecompressDXT4()
{
	// Can do color & alpha same as dxt5, but color is pre-multiplied 
	//   so the result will be wrong unless corrected. 
	if (!DecompressDXT5())
		return IL_FALSE;
	CorrectPreMult();

	return IL_FALSE;
}


ILboolean DecompressDXT5()
{
	int			x, y, z, i, j, k, Select;
	ILubyte		*Temp; //, r0, g0, b0, r1, g1, b1;
	Color8888	colours[4], *col;
	ILuint		bitmask, Offset;
	ILubyte		alphas[8], *alphamask;
	ILuint		bits;

	if (!CompData)
		return IL_FALSE;

	Temp = CompData;
	for (z = 0; z < Depth; z++) {
		for (y = 0; y < Height; y += 4) {
			for (x = 0; x < Width; x += 4) {
				if (y >= Height || x >= Width)
					break;
				alphas[0] = Temp[0];
				alphas[1] = Temp[1];
				alphamask = Temp + 2;
				Temp += 8;

				ReadColors(Temp, colours);
				bitmask = ((ILuint*)Temp)[1];
				UInt(&bitmask);
				Temp += 8;

				// Four-color block: derive the other two colors.    
				// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
				// These 2-bit codes correspond to the 2-bit fields 
				// stored in the 64-bit block.
				colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
				colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
				colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
				//colours[2].a = 0xFF;

				colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
				colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
				colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
				//colours[3].a = 0xFF;

				k = 0;
				for (j = 0; j < 4; j++) {
					for (i = 0; i < 4; i++, k++) {

						Select = (bitmask & (0x03 << k*2)) >> k*2;
						col = &colours[Select];

						// only put pixels out < width or height
						if (((x + i) < Width) && ((y + j) < Height)) {
							Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp;
							Image->Data[Offset + 0] = col->r;
							Image->Data[Offset + 1] = col->g;
							Image->Data[Offset + 2] = col->b;
						}
					}
				}

				// 8-alpha or 6-alpha block?    
				if (alphas[0] > alphas[1]) {    
					// 8-alpha block:  derive the other six alphas.    
					// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
					alphas[2] = (6 * alphas[0] + 1 * alphas[1] + 3) / 7;	// bit code 010
					alphas[3] = (5 * alphas[0] + 2 * alphas[1] + 3) / 7;	// bit code 011
					alphas[4] = (4 * alphas[0] + 3 * alphas[1] + 3) / 7;	// bit code 100
					alphas[5] = (3 * alphas[0] + 4 * alphas[1] + 3) / 7;	// bit code 101
					alphas[6] = (2 * alphas[0] + 5 * alphas[1] + 3) / 7;	// bit code 110
					alphas[7] = (1 * alphas[0] + 6 * alphas[1] + 3) / 7;	// bit code 111
				}
				else {
					// 6-alpha block.
					// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
					alphas[2] = (4 * alphas[0] + 1 * alphas[1] + 2) / 5;	// Bit code 010
					alphas[3] = (3 * alphas[0] + 2 * alphas[1] + 2) / 5;	// Bit code 011
					alphas[4] = (2 * alphas[0] + 3 * alphas[1] + 2) / 5;	// Bit code 100
					alphas[5] = (1 * alphas[0] + 4 * alphas[1] + 2) / 5;	// Bit code 101
					alphas[6] = 0x00;										// Bit code 110
					alphas[7] = 0xFF;										// Bit code 111
				}

				// Note: Have to separate the next two loops,
				//	it operates on a 6-byte system.

				// First three bytes
				//bits = *((ILint*)alphamask);
				bits = (alphamask[0]) | (alphamask[1] << 8) | (alphamask[2] << 16);
				for (j = 0; j < 2; j++) {
					for (i = 0; i < 4; i++) {
						// only put pixels out < width or height
						if (((x + i) < Width) && ((y + j) < Height)) {
							Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp + 3;
							Image->Data[Offset] = alphas[bits & 0x07];
						}
						bits >>= 3;
					}
				}

				// Last three bytes
				//bits = *((ILint*)&alphamask[3]);
				bits = (alphamask[3]) | (alphamask[4] << 8) | (alphamask[5] << 16);
				for (j = 2; j < 4; j++) {
					for (i = 0; i < 4; i++) {
						// only put pixels out < width or height
						if (((x + i) < Width) && ((y + j) < Height)) {
							Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp + 3;
							Image->Data[Offset] = alphas[bits & 0x07];
						}
						bits >>= 3;
					}
				}
			}
		}
	}

	return IL_TRUE;
}


ILboolean	Decompress3Dc()

{

	int			x, y, z, i, j, k, t1, t2;

	ILubyte		*Temp, *Temp2;

	ILubyte		XColours[8], YColours[8];

	ILuint		bitmask, bitmask2, Offset, CurrOffset;



	if (!CompData)

		return IL_FALSE;



	Temp = CompData;

	Offset = 0;

	for (z = 0; z < Depth; z++) {

		for (y = 0; y < Height; y += 4) {

			for (x = 0; x < Width; x += 4) {

				Temp2 = Temp + 8;



				//Read Y palette

				t1 = YColours[0] = Temp[0];

				t2 = YColours[1] = Temp[1];

				Temp += 2;

				if (t1 > t2)

					for (i = 2; i < 8; ++i)

						YColours[i] = t1 + ((t2 - t1)*(i - 1))/7;

				else {

					for (i = 2; i < 6; ++i)

						YColours[i] = t1 + ((t2 - t1)*(i - 1))/5;

					YColours[6] = 0;

					YColours[7] = 255;

				}



				// Read X palette

				t1 = XColours[0] = Temp2[0];

				t2 = XColours[1] = Temp2[1];

				Temp2 += 2;

				if (t1 > t2)

					for (i = 2; i < 8; ++i)

						XColours[i] = t1 + ((t2 - t1)*(i - 1))/7;

				else {

					for (i = 2; i < 6; ++i)

						XColours[i] = t1 + ((t2 - t1)*(i - 1))/5;

					XColours[6] = 0;

					XColours[7] = 255;

				}



				//decompress pixel data

				CurrOffset = Offset;

				for (k = 0; k < 4; k += 2) {

					// First three bytes

					bitmask = ((ILuint)(Temp[0]) << 0) | ((ILuint)(Temp[1]) << 8) | ((ILuint)(Temp[2]) << 16);

					bitmask2 = ((ILuint)(Temp2[0]) << 0) | ((ILuint)(Temp2[1]) << 8) | ((ILuint)(Temp2[2]) << 16);

					for (j = 0; j < 2; j++) {

						// only put pixels out < height

						if ((y + k + j) < Height) {

							for (i = 0; i < 4; i++) {

								// only put pixels out < width

								if (((x + i) < Width)) {

									ILint t, tx, ty;



									t1 = CurrOffset + (x + i)*3;

									Image->Data[t1 + 1] = ty = YColours[bitmask & 0x07];

									Image->Data[t1 + 0] = tx = XColours[bitmask2 & 0x07];



									//calculate b (z) component ((r/255)^2 + (g/255)^2 + (b/255)^2 = 1

									t = 127*128 - (tx - 127)*(tx - 128) - (ty - 127)*(ty - 128);

									if (t > 0)

										Image->Data[t1 + 2] = (ILubyte)(iSqrt(t) + 128);

									else

										Image->Data[t1 + 2] = 0x7F;

								}

								bitmask >>= 3;

								bitmask2 >>= 3;

							}

							CurrOffset += Image->Bps;

						}

					}

					Temp += 3;

					Temp2 += 3;

				}



				//skip bytes that were read via Temp2

				Temp += 8;

			}

			Offset += Image->Bps*4;

		}

	}



	return IL_TRUE;

}



ILboolean	DecompressAti1n()

{

	int			x, y, z, i, j, k, t1, t2;

	ILubyte		*Temp;

	ILubyte		Colours[8];

	ILuint		bitmask, Offset, CurrOffset;



	if (!CompData)

		return IL_FALSE;



	Temp = CompData;

	Offset = 0;

	for (z = 0; z < Depth; z++) {

		for (y = 0; y < Height; y += 4) {

			for (x = 0; x < Width; x += 4) {

				//Read palette

				t1 = Colours[0] = Temp[0];

				t2 = Colours[1] = Temp[1];

				Temp += 2;

				if (t1 > t2)

					for (i = 2; i < 8; ++i)

						Colours[i] = t1 + ((t2 - t1)*(i - 1))/7;

				else {

					for (i = 2; i < 6; ++i)

						Colours[i] = t1 + ((t2 - t1)*(i - 1))/5;

					Colours[6] = 0;

					Colours[7] = 255;

				}



				//decompress pixel data

				CurrOffset = Offset;

				for (k = 0; k < 4; k += 2) {

					// First three bytes

					bitmask = ((ILuint)(Temp[0]) << 0) | ((ILuint)(Temp[1]) << 8) | ((ILuint)(Temp[2]) << 16);

					for (j = 0; j < 2; j++) {

						// only put pixels out < height

						if ((y + k + j) < Height) {

							for (i = 0; i < 4; i++) {

								// only put pixels out < width

								if (((x + i) < Width)) {

									t1 = CurrOffset + (x + i);

									Image->Data[t1] = Colours[bitmask & 0x07];

								}

								bitmask >>= 3;

							}

							CurrOffset += Image->Bps;

						}

					}

					Temp += 3;

				}

			}

			Offset += Image->Bps*4;

		}

	}



	return IL_TRUE;

}



//This is nearly exactly the same as DecompressDXT5...

//I have to clean up this file (put common code in

//helper functions etc)

ILboolean DecompressRXGB()

{

	int			x, y, z, i, j, k, Select;

	ILubyte		*Temp;

	Color565	*color_0, *color_1;

	Color8888	colours[4], *col;

	ILuint		bitmask, Offset;

	ILubyte		alphas[8], *alphamask;

	ILuint		bits;



	if (!CompData)

		return IL_FALSE;



	Temp = CompData;

	for (z = 0; z < Depth; z++) {

		for (y = 0; y < Height; y += 4) {

			for (x = 0; x < Width; x += 4) {

				if (y >= Height || x >= Width)

					break;

				alphas[0] = Temp[0];

				alphas[1] = Temp[1];

				alphamask = Temp + 2;

				Temp += 8;

				color_0 = ((Color565*)Temp);

				color_1 = ((Color565*)(Temp+2));

				bitmask = ((ILuint*)Temp)[1];

				Temp += 8;



				colours[0].r = color_0->nRed << 3;

				colours[0].g = color_0->nGreen << 2;

				colours[0].b = color_0->nBlue << 3;

				colours[0].a = 0xFF;



				colours[1].r = color_1->nRed << 3;

				colours[1].g = color_1->nGreen << 2;

				colours[1].b = color_1->nBlue << 3;

				colours[1].a = 0xFF;



				// Four-color block: derive the other two colors.    

				// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3

				// These 2-bit codes correspond to the 2-bit fields 

				// stored in the 64-bit block.

				colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;

				colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;

				colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;

				colours[2].a = 0xFF;



				colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;

				colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;

				colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;

				colours[3].a = 0xFF;



				k = 0;

				for (j = 0; j < 4; j++) {

					for (i = 0; i < 4; i++, k++) {



						Select = (bitmask & (0x03 << k*2)) >> k*2;

						col = &colours[Select];



						// only put pixels out < width or height

						if (((x + i) < Width) && ((y + j) < Height)) {

							Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp;

							Image->Data[Offset + 0] = col->r;

							Image->Data[Offset + 1] = col->g;

							Image->Data[Offset + 2] = col->b;

						}

					}

				}



				// 8-alpha or 6-alpha block?    

				if (alphas[0] > alphas[1]) {    

					// 8-alpha block:  derive the other six alphas.    

					// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.

					alphas[2] = (6 * alphas[0] + 1 * alphas[1] + 3) / 7;	// bit code 010

					alphas[3] = (5 * alphas[0] + 2 * alphas[1] + 3) / 7;	// bit code 011

					alphas[4] = (4 * alphas[0] + 3 * alphas[1] + 3) / 7;	// bit code 100

					alphas[5] = (3 * alphas[0] + 4 * alphas[1] + 3) / 7;	// bit code 101

					alphas[6] = (2 * alphas[0] + 5 * alphas[1] + 3) / 7;	// bit code 110

					alphas[7] = (1 * alphas[0] + 6 * alphas[1] + 3) / 7;	// bit code 111

				}

				else {

					// 6-alpha block.

					// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.

					alphas[2] = (4 * alphas[0] + 1 * alphas[1] + 2) / 5;	// Bit code 010

					alphas[3] = (3 * alphas[0] + 2 * alphas[1] + 2) / 5;	// Bit code 011

					alphas[4] = (2 * alphas[0] + 3 * alphas[1] + 2) / 5;	// Bit code 100

					alphas[5] = (1 * alphas[0] + 4 * alphas[1] + 2) / 5;	// Bit code 101

					alphas[6] = 0x00;										// Bit code 110

					alphas[7] = 0xFF;										// Bit code 111

				}



				// Note: Have to separate the next two loops,

				//	it operates on a 6-byte system.

				// First three bytes

				bits = *((ILint*)alphamask);

				for (j = 0; j < 2; j++) {

					for (i = 0; i < 4; i++) {

						// only put pixels out < width or height

						if (((x + i) < Width) && ((y + j) < Height)) {

							Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp + 0;

							Image->Data[Offset] = alphas[bits & 0x07];

						}

						bits >>= 3;

					}

				}



				// Last three bytes

				bits = *((ILint*)&alphamask[3]);

				for (j = 2; j < 4; j++) {

					for (i = 0; i < 4; i++) {

						// only put pixels out < width or height

						if (((x + i) < Width) && ((y + j) < Height)) {

							Offset = z * Image->SizeOfPlane + (y + j) * Image->Bps + (x + i) * Image->Bpp + 0;

							Image->Data[Offset] = alphas[bits & 0x07];

						}

						bits >>= 3;

					}

				}

			}

		}

	}



	return IL_TRUE;

}



//stolen from OpenEXR

unsigned int

halfToFloat (unsigned short y)

{



	int s = (y >> 15) & 0x00000001;

	int e = (y >> 10) & 0x0000001f;

	int m =  y		  & 0x000003ff;



	if (e == 0)

	{

		if (m == 0)

		{

			//

			// Plus or minus zero

			//



			return s << 31;

		}

		else

		{

			//

			// Denormalized number -- renormalize it

			//



			while (!(m & 0x00000400))

			{

				m <<= 1;

				e -=  1;

			}



			e += 1;

			m &= ~0x00000400;

		}

	}

	else if (e == 31)

	{

		if (m == 0)

		{

			//

			// Positive or negative infinity

			//



			return (s << 31) | 0x7f800000;

		}

		else

		{

			//

			// Nan -- preserve sign and significand bits

			//



			return (s << 31) | 0x7f800000 | (m << 13);

		}

	}



	//

	// Normalized number

	//



	e = e + (127 - 15);

	m = m << 13;



	//

	// Assemble s, e and m.

	//



	return (s << 31) | (e << 23) | m;

}





ILboolean iConvFloat16ToFloat32(ILuint* dest, ILushort* src, ILuint size)

{

	ILuint i;

	for(i = 0; i < size; ++i, ++dest, ++src) {

		//float: 1 sign bit, 8 exponent bits, 23 mantissa bits

		//half: 1 sign bit, 5 exponent bits, 10 mantissa bits

		*dest = halfToFloat(*src);



	}

	return IL_TRUE;

}



ILboolean DecompressFloat()

{

	switch(CompFormat)

	{

		case PF_R32F:

		case PF_G32R32F:

		case PF_A32B32G32R32F:

			memcpy(Image->Data, CompData, Image->SizeOfData);

			return IL_TRUE;

		case PF_R16F:

		case PF_G16R16F:

		case PF_A16B16G16R16F:

			return iConvFloat16ToFloat32((ILuint*)Image->Data, (ILushort*)CompData,

				Image->Width * Image->Height * Image->Depth * Image->Bpp);

		default:

			return IL_FALSE;

	}

}


ILvoid CorrectPreMult()
{
	ILuint i;

	for (i = 0; i < Image->SizeOfData; i += 4) {
		if (Image->Data[i+3] != 0) {  // Cannot divide by 0.
			Image->Data[i]   = (ILubyte)(((ILuint)Image->Data[i]   << 8) / Image->Data[i+3]);
			Image->Data[i+1] = (ILubyte)(((ILuint)Image->Data[i+1] << 8) / Image->Data[i+3]);
			Image->Data[i+2] = (ILubyte)(((ILuint)Image->Data[i+2] << 8) / Image->Data[i+3]);
		}
	}

	return;
}


ILboolean DecompressARGB() {
	ILuint ReadI = 0, TempBpp, i;
	ILuint RedL, RedR;
	ILuint GreenL, GreenR;
	ILuint BlueL, BlueR;
	ILuint AlphaL, AlphaR;
	ILubyte	*Temp;


	if (!CompData)

		return IL_FALSE;



	if(CompFormat == PF_LUMINANCE && Head.RGBBitCount == 16 && Head.RBitMask == 0xFFFF) { //HACK

		memcpy(Image->Data, CompData, Image->SizeOfData);

		return IL_TRUE;

	}


	GetBitsFromMask(Head.RBitMask, &RedL, &RedR);
	GetBitsFromMask(Head.GBitMask, &GreenL, &GreenR);
	GetBitsFromMask(Head.BBitMask, &BlueL, &BlueR);
	GetBitsFromMask(Head.RGBAlphaBitMask, &AlphaL, &AlphaR);
	Temp = CompData;
	TempBpp = Head.RGBBitCount / 8;

	for (i = 0; i < Image->SizeOfData; i += Image->Bpp) {

		//TODO: This is SLOOOW...
		//but the old version crashed in release build under
		//winxp (and xp is right to stop this code - I always
		//wondered that it worked the old way at all)
		if (Image->SizeOfData - i < 4) { //less than 4 byte to write?
			if (TempBpp == 3) { //this branch is extra-SLOOOW
				ReadI =
					*Temp
					| ((*(Temp + 1)) << 8)
					| ((*(Temp + 2)) << 16);
			}
			else if (TempBpp == 1)
				ReadI = *((ILubyte*)Temp);
			else if (TempBpp == 2)
				ReadI = Temp[0] | (Temp[1] << 8);
		}
		else
			ReadI = Temp[0] | (Temp[1] << 8) | (Temp[2] << 16) | (Temp[3] << 24);
		Temp += TempBpp;

		Image->Data[i] = ((ReadI & Head.RBitMask) >> RedR) << RedL;

		if(Image->Bpp >= 3) {
			Image->Data[i+1] = ((ReadI & Head.GBitMask) >> GreenR) << GreenL;
			Image->Data[i+2] = ((ReadI & Head.BBitMask) >> BlueR) << BlueL;

			if (Image->Bpp == 4) {
				Image->Data[i+3] = ((ReadI & Head.RGBAlphaBitMask) >> AlphaR) << AlphaL;
				if (AlphaL >= 7) {
					Image->Data[i+3] = Image->Data[i+3] ? 0xFF : 0x00;
				}
				else if (AlphaL >= 4) {
					Image->Data[i+3] = Image->Data[i+3] | (Image->Data[i+3] >> 4);
				}
			}
		}
		else if (Image->Bpp == 2) {
			Image->Data[i+1] = ((ReadI & Head.RGBAlphaBitMask) >> AlphaR) << AlphaL;
			if (AlphaL >= 7) {
				Image->Data[i+1] = Image->Data[i+1] ? 0xFF : 0x00;
			}
			else if (AlphaL >= 4) {
				Image->Data[i+1] = Image->Data[i+1] | (Image->Data[i+3] >> 4);
			}
		}
	}

	return IL_TRUE;
}


// @TODO:  Look at using the BSF/BSR operands for inline ASM here.
ILvoid GetBitsFromMask(ILuint Mask, ILuint *ShiftLeft, ILuint *ShiftRight)
{
	ILuint Temp, i;

	if (Mask == 0) {
		*ShiftLeft = *ShiftRight = 0;
		return;
	}

	Temp = Mask;
	for (i = 0; i < 32; i++, Temp >>= 1) {
		if (Temp & 1)
			break;
	}
	*ShiftRight = i;

	// Temp is preserved, so use it again:
	for (i = 0; i < 8; i++, Temp >>= 1) {
		if (!(Temp & 1))
			break;
	}
	*ShiftLeft = 8 - i;

	return;
}


#if 0

//dxt extension code. this works, but it's to much to enable

//it for 1.6.8, especially because all these functions

//are not documented. perhaps we'll use it later, perhaps

//we'll delete it again, let's see.
ILubyte* ILAPIENTRY ilGetDxtcData()
{
	if (iCurImage == NULL) {
		ilSetError(IL_INTERNAL_ERROR);
		return NULL;
	}
	return iCurImage->DxtcData;
}

ILvoid ilFreeSurfaceDxtcData()
{
	if (iCurImage != NULL && iCurImage->DxtcData != NULL) {
		ifree(iCurImage->DxtcData);
		iCurImage->DxtcData = NULL;
		iCurImage->DxtcSize = 0;
		iCurImage->DxtcFormat = IL_DXT_NO_COMP;
	}
}

ILvoid ilFreeImageDxtcData()
{
	ILint i, j;
	ILuint ImgID = ilGetInteger(IL_CUR_IMAGE);
	ILint ImgCount = ilGetInteger(IL_NUM_IMAGES);
	ILint MipCount;

	for(i = 0; i <= ImgCount; ++i) {
		ilBindImage(ImgID);
		ilActiveImage(i);

		MipCount = ilGetInteger(IL_NUM_MIPMAPS);
		for(j = 0; j <= MipCount; ++j) {
			ilBindImage(ImgID);
			ilActiveImage(i);
			ilActiveMipmap(j);

			ilFreeSurfaceDxtcData();
		}
	}
}

/*
 * This assumes DxtcData, DxtcFormat, width, height, and depth are valid
 */
ILAPI ILboolean ILAPIENTRY ilDxtcDataToSurface()
{
	if (iCurImage == NULL || iCurImage->DxtcData == NULL) {
		ilSetError(IL_INVALID_PARAM);
		return IL_FALSE;
	}

	if (!(iCurImage->DxtcFormat == IL_DXT1 || iCurImage->DxtcFormat == IL_DXT3
		|| iCurImage->DxtcFormat == IL_DXT5)) {
		ilSetError(IL_INVALID_PARAM); //TODO
		return IL_FALSE;
	}


		//TODO: is this right for all dxt formats? works for
		//dxt1, 3, 5
		iCurImage->Bpp = 4;
		iCurImage->Bpc = 1;
		iCurImage->Bps = iCurImage->Width*iCurImage->Bpp*iCurImage->Bpc;
		iCurImage->SizeOfPlane = iCurImage->Height*iCurImage->Bps;
		iCurImage->Format = IL_RGBA;
		iCurImage->Type = IL_UNSIGNED_BYTE;

	if (iCurImage->SizeOfData != iCurImage->SizeOfPlane*iCurImage->Depth) {
		iCurImage->SizeOfData = iCurImage->Depth*iCurImage->SizeOfPlane;
		if (iCurImage->Data != NULL)
			ifree(iCurImage->Data);
		iCurImage->Data = NULL;
	}

	if (iCurImage->Data == NULL) {
		iCurImage->Data = ialloc(iCurImage->SizeOfData);
	}

	Image = iCurImage;
	Width = iCurImage->Width;
	Height = iCurImage->Height;
	Depth = iCurImage->Depth;
	switch(iCurImage->DxtcFormat)
	{
		case IL_DXT1: CompFormat = PF_DXT1; break;
		case IL_DXT3: CompFormat = PF_DXT3; break;
		case IL_DXT5: CompFormat = PF_DXT5; break;
	}
	CompData = iCurImage->DxtcData;
	Decompress(); //globals suck...fix this

        //TODO: origin should be set in Decompress()...
        iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
        return ilFixCur();
}

ILAPI ILboolean ILAPIENTRY ilDxtcDataToImage()
{
	ILint i, j;
	ILuint ImgID = ilGetInteger(IL_CUR_IMAGE);
	ILint ImgCount = ilGetInteger(IL_NUM_IMAGES);
	ILint MipCount;
	ILboolean ret = IL_TRUE;

	for(i = 0; i <= ImgCount; ++i) {
		ilBindImage(ImgID);
		ilActiveImage(i);

		MipCount = ilGetInteger(IL_NUM_MIPMAPS);
		for(j = 0; j <= MipCount; ++j) {
			ilBindImage(ImgID);
			ilActiveImage(i);
			ilActiveMipmap(j);

			if (!ilDxtcDataToSurface())
				ret = IL_FALSE;
		}
	}
        ilBindImage(ImgID);

	return ret;
}

ILAPI ILboolean ILAPIENTRY ilSurfaceToDxtcData(ILenum Format)
{
	ILuint Size;
	ILvoid* Data;
	ilFreeSurfaceDxtcData();

	Size = ilGetDXTCData(NULL, 0, Format);
	if (Size == 0) {
		return IL_FALSE;
	}

	Data = ialloc(Size);
    
	if (Data == NULL)
		return IL_FALSE;
            
	ilGetDXTCData(Data, Size, Format);

	//These have to be after the call to ilGetDXTCData()
	iCurImage->DxtcData = Data;
	iCurImage->DxtcFormat = Format;
	iCurImage->DxtcSize = Size;

	return IL_TRUE;
}

ILAPI ILboolean ILAPIENTRY ilImageToDxtcData(ILenum Format)
{
	ILint i, j;
	ILuint ImgID = ilGetInteger(IL_CUR_IMAGE);
	ILint ImgCount = ilGetInteger(IL_NUM_IMAGES);
	ILint MipCount;
	ILboolean ret = IL_TRUE;

	for(i = 0; i <= ImgCount; ++i) {
		ilBindImage(ImgID);
		ilActiveImage(i);

		MipCount = ilGetInteger(IL_NUM_MIPMAPS);
		for(j = 0; j <= MipCount; ++j) {
			ilBindImage(ImgID);
			ilActiveImage(i);
			ilActiveMipmap(j);

			if (!ilSurfaceToDxtcData(Format))
				ret = IL_FALSE;
		}
	}

	return ret;
}

//works like ilTexImage(), ie. destroys mipmaps etc (which sucks, but
//is consistent. There should be a ilTexSurface() and ilTexSurfaceDxtc()
//functions as well, but for now this is sufficient)
ILAPI ILboolean ILAPIENTRY ilTexImageDxtc(ILint w, ILint h, ILint d, ILenum DxtFormat, const ILubyte* data)
{
	ILimage* Image = iCurImage;

	ILint xBlocks, yBlocks, BlockSize, LineSize, DataSize;


	//The next few lines are copied from ilTexImage() and ilInitImage() -
	//should be factored in more reusable functions...

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

	////

	// Not sure if we should be getting rid of the palette...
	if (Image->Pal.Palette && Image->Pal.PalSize && Image->Pal.PalType != IL_PAL_NONE) {
		ifree(Image->Pal.Palette);
	}

	ilCloseImage(Image->Mipmaps);
	ilCloseImage(Image->Next);
	ilCloseImage(Image->Layers);

	if (Image->AnimList) ifree(Image->AnimList);
	if (Image->Profile)  ifree(Image->Profile);
	if (Image->DxtcData) ifree(Image->DxtcData);
	if (Image->Data)	 ifree(Image->Data);


	////

	memset (Image, 0, sizeof(ILimage));
	Image->Width	   = w;
	Image->Height	   = h;
	Image->Depth	   = d;

	//TODO: What about origin with dxtc data?
	Image->Origin	   = IL_ORIGIN_LOWER_LEFT;
	Image->Pal.PalType = IL_PAL_NONE;

        //alloc dxtc data buffer
	xBlocks = (w + 3)/4;
	yBlocks = (h + 3)/4;
	if (DxtFormat == IL_DXT1)
		BlockSize = 8;
	else
		BlockSize = 16;

	LineSize = xBlocks * BlockSize;

	DataSize = yBlocks * LineSize * d;

	Image->DxtcFormat  = DxtFormat;
        Image->DxtcSize = DataSize;
	Image->DxtcData    = ialloc(DataSize);

	if (Image->DxtcData == NULL) {
		return IL_FALSE;
	}

	if (data != NULL)
		memcpy(Image->DxtcData, data, DataSize);

	return IL_TRUE;
}


/* ------------------------------------------------------------------- */

ILvoid iFlipColorBlock(ILubyte *data)
{
    ILubyte tmp;

    tmp = data[4];
    data[4] = data[7];
    data[7] = tmp;

    tmp = data[5];
    data[5] = data[6];
    data[6] = tmp;
}

ILvoid iFlipSimpleAlphaBlock(ILushort *data)
{
	ILushort tmp;

	tmp = data[0];
	data[0] = data[3];
	data[3] = tmp;

	tmp = data[1];
	data[1] = data[2];
	data[2] = tmp;
}

ILvoid iComplexAlphaHelper(ILubyte* Data)
{
	ILushort tmp[2];

	//one 4 pixel line is 12 bit, copy each line into
	//a ushort, swap them and copy back
	tmp[0] = (Data[0] | (Data[1] << 8)) & 0xfff;
	tmp[1] = ((Data[1] >> 4) | (Data[2] << 4)) & 0xfff;

	Data[0] = tmp[1];
	Data[1] = (tmp[1] >> 8) | (tmp[0] << 4);
	Data[2] = tmp[0] >> 4;
}

ILvoid iFlipComplexAlphaBlock(ILubyte *Data)
{
	ILubyte tmp[3];
	Data += 2; //Skip 'palette'

	//swap upper two rows with lower two rows
	memcpy(tmp, Data, 3);
	memcpy(Data, Data + 3, 3);
	memcpy(Data + 3, tmp, 3);

	//swap 1st with 2nd row, 3rd with 4th
	iComplexAlphaHelper(Data);
	iComplexAlphaHelper(Data + 3);
}

ILvoid iFlipDxt1(ILubyte* data, ILuint count)
{
	ILint i;

	for (i = 0; i < count; ++i) {
		iFlipColorBlock(data);
		data += 8; //advance to next block
	}
}

ILvoid iFlipDxt3(ILubyte* data, ILuint count)
{
	ILint i;
	for (i = 0; i < count; ++i) {
		iFlipSimpleAlphaBlock((ILushort*)data);
		iFlipColorBlock(data + 8);
		data += 16; //advance to next block
	}
}

ILvoid iFlipDxt5(ILubyte* data, ILuint count)
{
	ILint i;
	for (i = 0; i < count; ++i) {
		iFlipComplexAlphaBlock(data);
		iFlipColorBlock(data + 8);
		data += 16; //advance to next block
	}
}

ILvoid iFlip3dc(ILubyte* data, ILuint count)
{
	ILint i;
	for (i = 0; i < count; ++i) {
		iFlipComplexAlphaBlock(data);
		iFlipComplexAlphaBlock(data + 8);
		data += 16; //advance to next block
	}
}


ILAPI ILvoid ILAPIENTRY ilFlipSurfaceDxtcData()
{
	ILint x, y, z;
	ILuint BlockSize, LineSize;
	ILubyte *Temp, *Runner, *Top, *Bottom;
	ILint numXBlocks, numYBlocks;
        ILvoid (*FlipBlocks)(ILubyte* data, ILuint count);

	if (iCurImage == NULL || iCurImage->DxtcData == NULL) {
		ilSetError(IL_INVALID_PARAM);
		return;
	}

	numXBlocks = (iCurImage->Width + 3)/4;
	numYBlocks = (iCurImage->Height + 3)/4;
	
	switch (iCurImage->DxtcFormat)
	{
		case IL_DXT1:
			BlockSize = 8;
			FlipBlocks = iFlipDxt1;
			break;
		case IL_DXT2:
		case IL_DXT3:
			BlockSize = 16;
			FlipBlocks = iFlipDxt3;
			break;
		case IL_DXT4:
		case IL_DXT5:
		case IL_RXGB:
			BlockSize = 16;
			FlipBlocks = iFlipDxt5;
			break;
		case IL_3DC:
			BlockSize = 16;
			FlipBlocks = iFlip3dc;
			break;
		default:
			ilSetError(IL_INVALID_PARAM);
			return;
	}
	
	LineSize = numXBlocks * BlockSize;
	Temp = ialloc(LineSize);

	if (Temp == NULL)
	    return;

	Runner = iCurImage->DxtcData;
	for (z = 0; z < iCurImage->Depth; ++z) {
		Top = Runner;
		Bottom = Runner + (numYBlocks - 1)*LineSize;
	    
		for (y = 0; y < numYBlocks/2; ++y) {
			//swap block row
			memcpy(Temp, Top, LineSize);
			memcpy(Top, Bottom, LineSize);
			memcpy(Bottom, Temp, LineSize);


			//swap blocks
			FlipBlocks(Top, numXBlocks);
			FlipBlocks(Bottom, numXBlocks);

			Top += LineSize;
			Bottom -= LineSize;
		}

		//middle line
		if (numYBlocks % 2 != 0)
			FlipBlocks(Top, numXBlocks);

		Runner += LineSize * numYBlocks;
	}

	ifree(Temp);
}

/**********************************************************************/

ILvoid iInvertDxt3Alpha(ILubyte *data)
{
	ILint i;

	for (i = 0; i < 8; ++i) {
		/*
		ILubyte b, t1, t2;
		b = data[i];

		t1 = b & 0xf;
		t1 = 15 - t1;
		t2 = b >> 4;
		t2 = 15 - t2;

		data[i] = (t2 << 4) | t1;
		*/
		//simpler:
		data[i] = ~data[i];
	}
}

ILvoid iInvertDxt5Alpha(ILubyte *data)
{
	ILubyte a0, a1;
	ILint i, j;

	a0 = data[0];
	a1 = data[1];

	//a0 > a1 <=> 255 - a0 < 255 - a1. Because of this,
	//a1 and a2 have to be swapped, and the indices
	//have to be changed as well.

	//invert and swap alpha
	data[0] = 255 - a1;
	data[1] = 255 - a0;
	data += 2;

	//fix indices
	const ILubyte map1[] = { 1, 0,  7, 6, 5, 4, 3, 2 };
	const ILubyte map2[] = { 1, 0,  5, 4, 3, 2,  7, 6 };
	for (i = 0; i < 6; i += 3) {
		ILuint in = data[i] | (data[i+1] << 8) | (data[i+2] << 16);
		ILuint out = 0;

		for (j = 0; j < 24; j += 3) {
			ILubyte b = (in >> j) & 0x7;

			if (a0 > a1)
				b = map1[b];
			else
				b = map2[b];

			out |= b << j;
		}

		data[i] = out;
		data[i+1] = out >> 8;
		data[i+2] = out >> 16;
	}
}

ILAPI ILvoid ILAPIENTRY ilInvertSurfaceDxtcDataAlpha()
{
	ILint i;
	ILuint BlockSize;
	ILubyte *Runner;
	ILint numXBlocks, numYBlocks, numBlocks;
	ILvoid (*InvertAlpha)(ILubyte* data);

	if (iCurImage == NULL || iCurImage->DxtcData == NULL) {
		ilSetError(IL_INVALID_PARAM);
		return;
	}

	numXBlocks = (iCurImage->Width + 3)/4;
	numYBlocks = (iCurImage->Height + 3)/4;
	numBlocks = numXBlocks*numYBlocks*iCurImage->Depth;
	BlockSize = 16;

	switch (iCurImage->DxtcFormat)
	{
		case IL_DXT3:
			InvertAlpha = iInvertDxt3Alpha;
			break;
		case IL_DXT5:
			InvertAlpha = iInvertDxt5Alpha;
			break;
		default:
			//DXT2/4 are not supported yet because nobody
			//uses them anyway and I would have to change
			//the color blocks as well...
			//DXT1 is not supported because DXT1 alpha is
			//seldom used and it's not easily invertable.
			ilSetError(IL_INVALID_PARAM);
			return;
	}

	Runner = iCurImage->DxtcData;
	for (i = 0; i < numBlocks; ++i, Runner += BlockSize) {
		InvertAlpha(Runner);
	}
}
#endif //dxt extension






#endif//IL_NO_DDS
