protected override void Initalize()
{
// Check to see if what we are dealing with is a PVR texture
if (!Is(encodedData))
{
throw new NotAValidTextureException("This is not a valid PVR texture.");
}
// Determine the offsets of the GBIX (if present) and PVRT header chunks.
if (PTMethods.Contains(encodedData, 0x00, gbixFourCC))
{
gbixOffset = 0x00;
pvrtOffset = 0x08 + BitConverter.ToInt32(encodedData, gbixOffset + 4);
}
else if (PTMethods.Contains(encodedData, 0x04, gbixFourCC))
{
gbixOffset = 0x04;
pvrtOffset = 0x0C + BitConverter.ToInt32(encodedData, gbixOffset + 4);
}
else if (PTMethods.Contains(encodedData, 0x04, pvrtFourCC))
{
gbixOffset = -1;
pvrtOffset = 0x04;
}
else
{
gbixOffset = -1;
pvrtOffset = 0x00;
}
// Read the global index (if it is present). If it is not present, just set it to 0.
if (gbixOffset != -1)
{
globalIndex = BitConverter.ToUInt32(encodedData, gbixOffset + 0x08);
}
else
{
globalIndex = 0;
}
// Read information about the texture
textureWidth = BitConverter.ToUInt16(encodedData, pvrtOffset + 0x0C);
textureHeight = BitConverter.ToUInt16(encodedData, pvrtOffset + 0x0E);
pixelFormat = (PvrPixelFormat)encodedData[pvrtOffset + 0x08];
dataFormat = (PvrDataFormat)encodedData[pvrtOffset + 0x09];
// Get the codecs and make sure we can decode using them
pixelCodec = PvrPixelCodec.GetPixelCodec(pixelFormat);
dataCodec = PvrDataCodec.GetDataCodec(dataFormat);
if (dataCodec != null && pixelCodec != null)
{
dataCodec.PixelCodec = pixelCodec;
canDecode = true;
}
// Set the number of palette entries
// The number in a Small Vq encoded texture various based on its size
paletteEntries = dataCodec.PaletteEntries;
if (dataFormat == PvrDataFormat.SmallVq || dataFormat == PvrDataFormat.SmallVqMipmaps)
{
if (textureWidth <= 16)
{
paletteEntries = 64; // Actually 16
}
else if (textureWidth <= 32)
{
paletteEntries = 256; // Actually 64
}
else if (textureWidth <= 64)
{
paletteEntries = 512; // Actually 128
}
else
{
paletteEntries = 1024; // Actually 256
}
}
// Set the palette and data offsets
if (!canDecode || paletteEntries == 0 || dataCodec.NeedsExternalPalette)
{
paletteOffset = -1;
dataOffset = pvrtOffset + 0x10;
}
else
{
paletteOffset = pvrtOffset + 0x10;
dataOffset = paletteOffset + (paletteEntries * (pixelCodec.Bpp >> 3));
}
// Get the compression format and determine if we need to decompress this texture
compressionFormat = GetCompressionFormat(encodedData, pvrtOffset, dataOffset);
compressionCodec = PvrCompressionCodec.GetCompressionCodec(compressionFormat);
if (compressionFormat != PvrCompressionFormat.None && compressionCodec != null)
{
encodedData = compressionCodec.Decompress(encodedData, dataOffset, pixelCodec, dataCodec);
// Now place the offsets in the appropiate area
if (compressionFormat == PvrCompressionFormat.Rle)
{
if (gbixOffset != -1) gbixOffset -= 4;
pvrtOffset -= 4;
if (paletteOffset != -1) paletteOffset -= 4;
dataOffset -= 4;
}
}
// If the texture contains mipmaps, gets the offsets of them
if (canDecode && dataCodec.HasMipmaps)
{
mipmapOffsets = new int[(int)Math.Log(textureWidth, 2) + 1];
int mipmapOffset = 0;
// Calculate the padding for the first mipmap offset
if (dataFormat == PvrDataFormat.SquareTwiddledMipmaps)
{
// A 1x1 mipmap takes up as much space as a 2x1 mipmap
mipmapOffset = (dataCodec.Bpp) >> 3;
}
else if (dataFormat == PvrDataFormat.SquareTwiddledMipmapsAlt)
{
// A 1x1 mipmap takes up as much space as a 2x2 mipmap
mipmapOffset = (3 * dataCodec.Bpp) >> 3;
}
for (int i = mipmapOffsets.Length - 1, size = 1; i >= 0; i--, size <<= 1)
{
mipmapOffsets[i] = mipmapOffset;
mipmapOffset += Math.Max((size * size * dataCodec.Bpp) >> 3, 1);
}
}
initalized = true;
}