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, Encoding.UTF8.GetBytes("GBIX"))) { gbixOffset = 0x00; pvrtOffset = 0x10; } else if (PTMethods.Contains(encodedData, 0x04, Encoding.UTF8.GetBytes("GBIX"))) { gbixOffset = 0x04; pvrtOffset = 0x14; } else if (PTMethods.Contains(encodedData, 0x04, Encoding.UTF8.GetBytes("PVRT"))) { 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 palette and data offsets if (!canDecode || dataCodec.PaletteEntries == 0 || dataCodec.NeedsExternalPalette) { paletteOffset = -1; dataOffset = pvrtOffset + 0x10; } else { paletteOffset = pvrtOffset + 0x10; dataOffset = paletteOffset + (dataCodec.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; } 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; }
protected override MemoryStream EncodeTexture() { // Calculate what the length of the texture will be int textureLength = 16 + (textureWidth * textureHeight * dataCodec.Bpp / 8); if (hasGlobalIndex) { textureLength += 16; } if (dataCodec.PaletteEntries != 0 && !dataCodec.NeedsExternalPalette) { textureLength += (dataCodec.PaletteEntries * pixelCodec.Bpp / 8); } // Calculate the mipmap padding (if the texture contains mipmaps) int mipmapPadding = 0; if (dataCodec.HasMipmaps) { if (dataFormat == PvrDataFormat.SquareTwiddledMipmaps) { // A 1x1 mipmap takes up as much space as a 2x1 mipmap mipmapPadding = (dataCodec.Bpp) >> 3; } else if (dataFormat == PvrDataFormat.SquareTwiddledMipmapsAlt) { // A 1x1 mipmap takes up as much space as a 2x2 mipmap mipmapPadding = (3 * dataCodec.Bpp) >> 3; } textureLength += mipmapPadding; for (int size = 1; size < textureWidth; size <<= 1) { textureLength += Math.Max((size * size * dataCodec.Bpp) >> 3, 1); } } MemoryStream destination = new MemoryStream(textureLength); // Write out the GBIX header (if we are including one) if (hasGlobalIndex) { destination.WriteByte((byte)'G'); destination.WriteByte((byte)'B'); destination.WriteByte((byte)'I'); destination.WriteByte((byte)'X'); PTStream.WriteUInt32(destination, 8); PTStream.WriteUInt32(destination, globalIndex); PTStream.WriteUInt32(destination, 0); } // Write out the PVRT header destination.WriteByte((byte)'P'); destination.WriteByte((byte)'V'); destination.WriteByte((byte)'R'); destination.WriteByte((byte)'T'); if (hasGlobalIndex) { PTStream.WriteInt32(destination, textureLength - 24); } else { PTStream.WriteInt32(destination, textureLength - 8); } destination.WriteByte((byte)pixelFormat); destination.WriteByte((byte)dataFormat); PTStream.WriteUInt16(destination, 0); PTStream.WriteUInt16(destination, textureWidth); PTStream.WriteUInt16(destination, textureHeight); // If we have an internal palette, write it if (dataCodec.PaletteEntries != 0 && !dataCodec.NeedsExternalPalette) { byte[] palette = pixelCodec.EncodePalette(texturePalette, dataCodec.PaletteEntries); destination.Write(palette, 0, palette.Length); } // Write out any mipmaps if (dataCodec.HasMipmaps) { // Write out any padding bytes before the 1x1 mipmap for (int i = 0; i < mipmapPadding; i++) { destination.WriteByte(0); } for (int size = 1; size < textureWidth; size <<= 1) { byte[] mipmapDecodedData = BitmapToRawResized(decodedBitmap, size, 1); byte[] mipmapTextureData = dataCodec.Encode(mipmapDecodedData, 0, size, size); destination.Write(mipmapTextureData, 0, mipmapTextureData.Length); } } // Write the texture data byte[] textureData = dataCodec.Encode(decodedData, textureWidth, textureHeight, null); destination.Write(textureData, 0, textureData.Length); // Compress the texture if (compressionFormat != PvrCompressionFormat.None) { compressionCodec = PvrCompressionCodec.GetCompressionCodec(compressionFormat); if (compressionCodec != null) { // Ok, we need to convert the current stream to an array, compress it, then write it back to a new stream byte[] buffer = destination.ToArray(); buffer = compressionCodec.Compress(buffer, (hasGlobalIndex ? 0x20 : 0x10), pixelCodec, dataCodec); destination = new MemoryStream(); destination.Write(buffer, 0, buffer.Length); } } return(destination); }