private void InitWithKTXTexture(BinaryReader reader) { var identifier = reader.ReadBytes(12); if (identifier[1] != 'K' || identifier[2] != 'T' || identifier[3] != 'X') { throw new InvalidDataException("Invalid KTX header"); } var endiannes = reader.ReadUInt32(); if (endiannes != 0x04030201) { throw new InvalidDataException("Unsupported endiannes"); } var glType = reader.ReadInt32(); var glTypeSize = reader.ReadInt32(); var glFormat = reader.ReadInt32(); var glInternalFormat = reader.ReadInt32(); var glBaseInternalFormat = reader.ReadInt32(); var pixelWidth = reader.ReadInt32(); var pixelHeight = reader.ReadInt32(); var pixelDepth = reader.ReadInt32(); var numberOfArrayElements = reader.ReadInt32(); var numberOfFaces = reader.ReadInt32(); var numberOfMipmapLevels = reader.ReadInt32(); var bytesOfKeyValueData = reader.ReadInt32(); reader.ReadBytes(bytesOfKeyValueData); if (numberOfArrayElements != 0) { throw new InvalidDataException("Array textures are not supported"); } if (numberOfFaces != 1) { throw new InvalidDataException("Cubemap textures are not supported"); } if (pixelDepth != 0) { throw new InvalidDataException("3D Textures are not supported"); } if ((pixelWidth & 3) != 0 || (pixelHeight & 3) != 0) { throw new InvalidDataException("Texture dimensions should multiple of 4"); } SurfaceSize = ImageSize = new Size(pixelWidth, pixelHeight); Action glCommands = PrepareOpenGLTexture; PrepareOpenGLTexture(); for (int i = 0; i < Math.Max(1, numberOfMipmapLevels); i++) { var dataLength = reader.ReadInt32(); MemoryUsed = 0; if (i > 0 && (pixelWidth < 8 || pixelHeight < 8)) { continue; } // Copy variables because they will be captured. int mipLevel = i; int width = pixelWidth; int height = pixelHeight; if (glFormat == 0) { var data = ReadTextureData(reader, dataLength); glCommands += () => { if (!etc2Checked) { etc2Checked = true; if (PlatformRenderer.GetGLESMajorVersion() >= 3) { etc2Supported = true; } else { var ext = GL.GetString(StringName.Extensions); etc2Supported = ext?.Contains("ETC2_RGBA8") ?? false; } Debug.Write(etc2Supported ? "ETC2 textures supported." : "ETC2 textures not supported."); } PlatformRenderer.PushTexture(handle, 0); const int etc1Rgb8Oes = 36196; if (etc2Supported || (Application.Platform == PlatformId.Android && glInternalFormat == etc1Rgb8Oes)) { GL.CompressedTexImage2D( TextureTarget.Texture2D, mipLevel, (PixelInternalFormat)glInternalFormat, width, height, 0, dataLength, data); } else { var rgba8Data = Marshal.AllocHGlobal(width * height * 4); Etc2Decoder.Decode(data, rgba8Data, width, height, glInternalFormat); GL.TexImage2D(TextureTarget.Texture2D, mipLevel, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, rgba8Data); Marshal.FreeHGlobal(rgba8Data); } PlatformRenderer.PopTexture(0); PlatformRenderer.CheckErrors(); }; } else { var data = ReadTextureData(reader, dataLength); glCommands += () => { PlatformRenderer.PushTexture(handle, 0); GL.TexImage2D( TextureTarget.Texture2D, mipLevel, (PixelInternalFormat)glInternalFormat, width, height, 0, (PixelFormat)glFormat, (PixelType)glType, data); PlatformRenderer.PopTexture(0); PlatformRenderer.CheckErrors(); }; } pixelWidth /= 2; pixelHeight /= 2; } Application.InvokeOnMainThread(glCommands); }
private void InitWithKTXTexture(BinaryReader reader) { var identifier = reader.ReadBytes(12); if (identifier[1] != 'K' || identifier[2] != 'T' || identifier[3] != 'X') { throw new InvalidDataException("Invalid KTX header"); } var endiannes = reader.ReadUInt32(); if (endiannes != 0x04030201) { throw new InvalidDataException("Unsupported endiannes"); } var glType = reader.ReadInt32(); var glTypeSize = reader.ReadInt32(); var glFormat = reader.ReadInt32(); var glInternalFormat = reader.ReadInt32(); var glBaseInternalFormat = reader.ReadInt32(); var pixelWidth = reader.ReadInt32(); var pixelHeight = reader.ReadInt32(); var pixelDepth = reader.ReadInt32(); var numberOfArrayElements = reader.ReadInt32(); var numberOfFaces = reader.ReadInt32(); var numberOfMipmapLevels = Math.Max(1, reader.ReadInt32()); var bytesOfKeyValueData = reader.ReadInt32(); reader.ReadBytes(bytesOfKeyValueData); if (numberOfArrayElements != 0) { throw new InvalidDataException("Array textures are not supported"); } if (numberOfFaces != 1) { throw new InvalidDataException("Cubemap textures are not supported"); } if (pixelDepth != 0) { throw new InvalidDataException("3D Textures are not supported"); } if ((pixelWidth & 3) != 0 || (pixelHeight & 3) != 0) { throw new InvalidDataException("Texture dimensions should multiple of 4"); } if (numberOfMipmapLevels > 1 && numberOfMipmapLevels != GraphicsUtility.CalculateMipLevelCount(pixelWidth, pixelHeight)) { throw new InvalidDataException(); } var format = ConvertGLFormat(glInternalFormat, glBaseInternalFormat, glFormat, glType); var etcFormat = format == Format.ETC1_R8G8B8_UNorm_Block || format == Format.ETC2_R8G8B8_UNorm_Block || format == Format.ETC2_R8G8B8A1_UNorm_Block || format == Format.ETC2_R8G8B8A8_UNorm_Block; SurfaceSize = ImageSize = new Size(pixelWidth, pixelHeight); Action deferredCommands = null; for (int level = 0; level < numberOfMipmapLevels; level++) { var levelCopy = level; var dataLength = reader.ReadInt32(); var data = ReadTextureData(reader, dataLength); GraphicsUtility.CalculateMipLevelSize(levelCopy, pixelWidth, pixelHeight, out var levelWidth, out var levelHeight); MemoryUsed = 0; deferredCommands += () => { var formatFeatures = PlatformRenderer.Context.GetFormatFeatures(format); if (etcFormat && (formatFeatures & FormatFeatures.Sample) == 0) { var rgba8Data = Marshal.AllocHGlobal(levelWidth * levelHeight * 4); try { Etc2Decoder.Decode(data, rgba8Data, levelWidth, levelHeight, format); EnsurePlatformTexture(Format.R8G8B8A8_UNorm, pixelWidth, pixelHeight, numberOfMipmapLevels > 1); platformTexture.SetData(levelCopy, rgba8Data); } finally { Marshal.FreeHGlobal(rgba8Data); } } else { EnsurePlatformTexture(format, pixelWidth, pixelHeight, numberOfMipmapLevels > 1); platformTexture.SetData(levelCopy, data); } }; } Window.Current.InvokeOnRendering(deferredCommands); }