private unsafe void uploadATFTextureFromByteArray(ByteArray data, uint byteArrayOffset) { data.position = byteArrayOffset; // read atf signature string signature = data.readUTFBytes(3); if (signature != "ATF") { throw new InvalidDataException("ATF signature not found"); } // read atf length uint length = readUInt24(data); if ((byteArrayOffset + length) > data.length) { throw new InvalidDataException("ATF length exceeds byte array length"); } // get format uint tdata = data.readUnsignedByte( ); AtfType type = (AtfType)(tdata >> 7); if (type != AtfType.NORMAL) { throw new NotImplementedException("ATF Cube maps are not supported"); } // Removing ATF format limitation to allow for multiple format support. // AtfFormat format = (AtfFormat)(tdata & 0x7f); // if (format != AtfFormat.Block) { // throw new NotImplementedException("Only ATF block compressed textures are supported"); // } // get dimensions int width = (1 << (int)data.readUnsignedByte()); int height = (1 << (int)data.readUnsignedByte()); if (width != mWidth || height != mHeight) { throw new InvalidDataException("ATF Width and height dont match"); } // get mipmap count int mipCount = (int)data.readUnsignedByte(); // read all mipmap levels for (int level = 0; level < mipCount; level++) { // read all gpu formats for (int gpuFormat = 0; gpuFormat < 3; gpuFormat++) { // read block length uint blockLength = readUInt24(data); if ((data.position + blockLength) > data.length) { throw new System.IO.InvalidDataException("Block length exceeds ATF file length"); } if (blockLength > 0) { // handle PVRTC on iOS if (gpuFormat == 1) { #if PLATFORM_MONOTOUCH OpenTK.Graphics.ES20.PixelInternalFormat pixelFormat = (OpenTK.Graphics.ES20.PixelInternalFormat) 0x8C02; fixed(byte *ptr = data.getRawArray()) { // upload from data position var address = new IntPtr(ptr + data.position); GL.CompressedTexImage2D(textureTarget, level, pixelFormat, width, height, 0, (int)blockLength, address); mAllocated = true; } trackCompressedMemoryUsage((int)blockLength); #endif } else if (gpuFormat == 2) { #if PLATFORM_MONODROID int textureLength = width * height / 2; fixed(byte *ptr = data.getRawArray()) { var address = new IntPtr(ptr + data.position); GL.CompressedTexImage2D(textureTarget, level, All.Etc1Rgb8Oes, width, height, 0, (int)textureLength, address); GLUtils.CheckGLError(); mAllocated = true; if (textureLength < blockLength) { mAlphaTexture = new Texture(mContext, width, height, mFormat, mOptimizeForRenderToTexture, mStreamingLevels); var alphaAddress = new IntPtr(ptr + data.position + textureLength); GL.BindTexture(mAlphaTexture.textureTarget, mAlphaTexture.textureId); GLUtils.CheckGLError(); GL.CompressedTexImage2D(mAlphaTexture.textureTarget, level, All.Etc1Rgb8Oes, width, height, 0, textureLength, alphaAddress); GLUtils.CheckGLError(); GL.BindTexture(mAlphaTexture.textureTarget, 0); GLUtils.CheckGLError(); mAllocated = true; } else { mAlphaTexture = new Texture(mContext, 1, 1, mFormat, mOptimizeForRenderToTexture, mStreamingLevels); var clearData = new BitmapData(width, height, true, 0xFFFFFFFF); GL.BindTexture(mAlphaTexture.textureTarget, mAlphaTexture.textureId); GLUtils.CheckGLError(); GL.TexImage2D(mAlphaTexture.textureTarget, level, (int)PixelInternalFormat.Rgba, 1, 1, 0, PixelFormat.Rgba, PixelType.UnsignedByte, clearData.getRawData()); GLUtils.CheckGLError(); GL.BindTexture(mAlphaTexture.textureTarget, 0); GLUtils.CheckGLError(); mAllocated = true; clearData.dispose(); } } trackCompressedMemoryUsage((int)blockLength); #endif } // TODO handle other formats/platforms } // next block data data.position += blockLength; } } }
private unsafe void uploadATFTextureFromByteArray(ByteArray data, uint byteArrayOffset) { data.position = byteArrayOffset; // read atf signature string signature = data.readUTFBytes(3); if (signature != "ATF") { throw new InvalidDataException("ATF signature not found"); } // read atf length uint length = readUInt24(data); if ((byteArrayOffset + length) > data.length) { throw new InvalidDataException("ATF length exceeds byte array length"); } // get format uint tdata = data.readUnsignedByte( ); AtfType type = (AtfType)(tdata >> 7); if (type != AtfType.NORMAL) { throw new NotImplementedException("ATF Cube maps are not supported"); } // Removing ATF format limitation to allow for multiple format support. // AtfFormat format = (AtfFormat)(tdata & 0x7f); // if (format != AtfFormat.Block) { // throw new NotImplementedException("Only ATF block compressed textures are supported"); // } // get dimensions int width = (1 << (int)data.readUnsignedByte()); int height = (1 << (int)data.readUnsignedByte()); if (width != mWidth || height != mHeight) { throw new InvalidDataException("ATF Width and height dont match"); } // get mipmap count int mipCount = (int)data.readUnsignedByte(); // read all mipmap levels for (int level = 0; level < mipCount; level++) { // read all gpu formats for (int gpuFormat = 0; gpuFormat < 3; gpuFormat++) { // read block length uint blockLength = readUInt24(data); if ((data.position + blockLength) > data.length) { throw new System.IO.InvalidDataException("Block length exceeds ATF file length"); } if (blockLength > 0) { #if PLATFORM_MONOTOUCH // handle PVRTC on iOS if (gpuFormat == 1) { OpenTK.Graphics.ES20.PixelInternalFormat pixelFormat = (OpenTK.Graphics.ES20.PixelInternalFormat) 0x8C02; fixed(byte *ptr = data.getRawArray()) { // upload from data position var address = new IntPtr(ptr + data.position); GL.CompressedTexImage2D(textureTarget, level, pixelFormat, width, height, 0, (int)blockLength, address); } } #endif // TODO handle other formats/platforms } // next block data data.position += blockLength; } } }