/// <summary> /// Decodes the specified level of the encoded texture to an array of RGBA8 pixels. /// </summary> /// <param name="level">The level of the texture to decode.</param> /// <param name="desiredStride">Desired stride (number of bytes per scanline) of the result.</param> /// <returns>An array with the RGBA8 data of the level (with no extra row padding).</returns> public byte[] DecodeLevelToRGBA8(int level, int desiredStride) { if (level < 0 || level >= LevelCount) { throw new ArgumentOutOfRangeException("level"); } if (desiredStride < 0) { throw new ArgumentOutOfRangeException("desiredStride"); } int levelWidth = WidthOfLevel(level), levelHeight = HeightOfLevel(level); if (desiredStride < levelWidth * 4) { throw new ArgumentOutOfRangeException("desiredStride", "Stride is too small to contain a row of data."); } // Decode texture as RGBA8 (GcTextureDecode format) byte[] decodedData = new byte[levelHeight * desiredStride]; GcTextureFormatCodec.GetCodec(format).DecodeTexture(decodedData, 0, levelWidth, levelHeight, desiredStride, encodedLevelData[level], 0, null, 0); return(decodedData); }
/// <summary> /// Calculates the size of a level of the texture. /// </summary> /// <param name="level">The level of the texture.</param> /// <param name="replicateCmprBug">true to replicate the F-Zero GX CMPR encoding bug.</param> /// <returns>The size of the encoded data in the specified level.</returns> private int CalculateSizeOfLevel(int level) { // Here we allow also to specify the "next" level for easier implementation // of the methods that encode the new texture if (level < 0 || level > LevelCount) { throw new ArgumentOutOfRangeException("level"); } int levelWidth = width >> level, levelHeight = height >> level; return(GcTextureFormatCodec.GetCodec(format).CalcTextureSize(levelWidth, levelHeight)); }
private Texture2D ReadTexture(FileStream fs, EndianBinaryReader reader, int height, int width, LibGC.Texture.GcTextureFormat format) { GcTextureFormatCodec codec = GcTextureFormatCodec.GetCodec(format); int byteSize = codec.CalcTextureSize(width, height); //int stride = (width / block_width) * bpp / 8; int stride = width * 4; byte[] imageData = reader.ReadBytes(byteSize); Texture2D tex = new Texture2D(width, height, TextureFormat.RGBA32, false); byte[] destData = new byte[width * height * 4]; codec.DecodeTexture(destData, 0, width, height, stride, imageData, 0, null, 0); tex.LoadRawTextureData(destData); tex.Apply(); return(tex); }
/// <summary> /// Create or replace the specified texture level from the specified image data. /// New texture levels must be created in order. /// </summary> /// <param name="level">The level of the texture to create or replace.</param> /// <param name="newImageDataStride">The stride (number of bytes per row) of the new image data.</param> /// <param name="newImageData">The new image data for the level.</param> public void DefineLevelData(int level, int newImageDataStride, byte[] newImageData) { if (level > LevelCount) // We allow to either replace an existing level or to generate the next level { throw new ArgumentOutOfRangeException("level"); } if (newImageDataStride < 0) { throw new ArgumentOutOfRangeException("newImageDataStride"); } if (newImageData == null) { throw new ArgumentNullException("newImageData"); } // Check that this texture level can be defined (size is not too small) // This checks that width and height can be divided evenly by 2^level if ((width & ((1 << level) - 1)) != 0 || (height & ((1 << level) - 1)) != 0) { throw new ArgumentOutOfRangeException("level", "Level is too low for the image dimensions."); } int levelWidth = width >> level; int levelHeight = height >> level; if (newImageDataStride < levelWidth * 4) { throw new ArgumentOutOfRangeException("newImageDataStride", "Stride is too small to contain a row of data."); } // Adding a new mipmap? if (level == LevelCount) { encodedLevelData.Add(new byte[CalculateSizeOfLevel(level)]); } // Encode GcTextureFormatCodec.GetCodec(format).EncodeTexture( newImageData, 0, levelWidth, levelHeight, newImageDataStride, encodedLevelData[level], 0, null, 0); }