public SKBitmap GenerateBitmap() { Reader.BaseStream.Position = DataOffset; var width = ActualWidth >> MipmapLevelToExtract; var height = ActualHeight >> MipmapLevelToExtract; var blockWidth = Width >> MipmapLevelToExtract; var blockHeight = Height >> MipmapLevelToExtract; var skiaBitmap = new SKBitmap(width, height, SKColorType.Bgra8888, SKAlphaType.Unpremul); SkipMipmaps(); switch (Format) { case VTexFormat.DXT1: return(TextureDecompressors.UncompressDXT1(skiaBitmap, GetTextureSpan(), blockWidth, blockHeight)); case VTexFormat.DXT5: var yCoCg = false; var normalize = false; var invert = false; var hemiOct = false; if (Resource.EditInfo.Structs.ContainsKey(ResourceEditInfo.REDIStruct.SpecialDependencies)) { var specialDeps = (SpecialDependencies)Resource.EditInfo.Structs[ResourceEditInfo.REDIStruct.SpecialDependencies]; yCoCg = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version Image YCoCg Conversion"); normalize = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version Image NormalizeNormals"); invert = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version LegacySource1InvertNormals"); hemiOct = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version Mip HemiOctAnisoRoughness"); } return(TextureDecompressors.UncompressDXT5(skiaBitmap, GetTextureSpan(), blockWidth, blockHeight, yCoCg, normalize, invert, hemiOct)); case VTexFormat.I8: return(TextureDecompressors.ReadI8(skiaBitmap, GetTextureSpan())); case VTexFormat.RGBA8888: return(TextureDecompressors.ReadRGBA8888(skiaBitmap, GetTextureSpan())); case VTexFormat.R16: return(TextureDecompressors.ReadR16(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RG1616: return(TextureDecompressors.ReadRG1616(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RGBA16161616: return(TextureDecompressors.ReadRGBA16161616(skiaBitmap, GetTextureSpan())); case VTexFormat.R16F: return(TextureDecompressors.ReadR16F(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RG1616F: return(TextureDecompressors.ReadRG1616F(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RGBA16161616F: return(TextureDecompressors.ReadRGBA16161616F(skiaBitmap, GetTextureSpan())); case VTexFormat.R32F: return(TextureDecompressors.ReadR32F(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RG3232F: return(TextureDecompressors.ReadRG3232F(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RGB323232F: return(TextureDecompressors.ReadRGB323232F(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RGBA32323232F: return(TextureDecompressors.ReadRGBA32323232F(GetDecompressedBuffer(), Width, Height)); case VTexFormat.BC6H: return(BPTC.BPTCDecoders.UncompressBC6H(GetDecompressedBuffer(), Width, Height)); case VTexFormat.BC7: bool hemiOctRB = false; invert = false; if (Resource.EditInfo.Structs.ContainsKey(ResourceEditInfo.REDIStruct.SpecialDependencies)) { var specialDeps = (SpecialDependencies)Resource.EditInfo.Structs[ResourceEditInfo.REDIStruct.SpecialDependencies]; hemiOctRB = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version Mip HemiOctIsoRoughness_RG_B"); invert = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version LegacySource1InvertNormals"); } return(BPTC.BPTCDecoders.UncompressBC7(GetDecompressedBuffer(), Width, Height, hemiOctRB, invert)); case VTexFormat.ATI2N: normalize = false; if (Resource.EditInfo.Structs.ContainsKey(ResourceEditInfo.REDIStruct.SpecialDependencies)) { var specialDeps = (SpecialDependencies)Resource.EditInfo.Structs[ResourceEditInfo.REDIStruct.SpecialDependencies]; normalize = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version Image NormalizeNormals"); } return(TextureDecompressors.UncompressATI2N(skiaBitmap, GetTextureSpan(), Width, Height, normalize)); case VTexFormat.IA88: return(TextureDecompressors.ReadIA88(skiaBitmap, GetTextureSpan())); case VTexFormat.ATI1N: return(TextureDecompressors.UncompressATI1N(skiaBitmap, GetTextureSpan(), Width, Height)); // TODO: Are we sure DXT5 and RGBA8888 are just raw buffers? case VTexFormat.JPEG_DXT5: case VTexFormat.JPEG_RGBA8888: case VTexFormat.PNG_DXT5: case VTexFormat.PNG_RGBA8888: return(ReadBuffer()); case VTexFormat.ETC2: // TODO: Rewrite EtcDecoder to work on skia span directly var etc = new Etc.EtcDecoder(); var data = new byte[skiaBitmap.RowBytes * skiaBitmap.Height]; etc.DecompressETC2(GetDecompressedTextureAtMipLevel(0), width, height, data); var gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned); skiaBitmap.InstallPixels(skiaBitmap.Info, gcHandle.AddrOfPinnedObject(), skiaBitmap.RowBytes, (address, context) => { gcHandle.Free(); }, null); break; case VTexFormat.ETC2_EAC: // TODO: Rewrite EtcDecoder to work on skia span directly var etc2 = new Etc.EtcDecoder(); var data2 = new byte[skiaBitmap.RowBytes * skiaBitmap.Height]; etc2.DecompressETC2A8(GetDecompressedTextureAtMipLevel(0), width, height, data2); var gcHandle2 = GCHandle.Alloc(data2, GCHandleType.Pinned); skiaBitmap.InstallPixels(skiaBitmap.Info, gcHandle2.AddrOfPinnedObject(), skiaBitmap.RowBytes, (address, context) => { gcHandle2.Free(); }, null); break; case VTexFormat.BGRA8888: return(TextureDecompressors.ReadBGRA8888(skiaBitmap, GetTextureSpan())); default: throw new NotImplementedException(string.Format("Unhandled image type: {0}", Format)); } return(skiaBitmap); }
public SKBitmap GenerateBitmap() { Reader.BaseStream.Position = DataOffset; var width = NonPow2Width > 0 ? NonPow2Width : Width; var height = NonPow2Height > 0 ? NonPow2Height : Height; var imageInfo = new SKImageInfo(width, height, SKColorType.Bgra8888, SKAlphaType.Unpremul); Span <byte> data = new byte[imageInfo.RowBytes * imageInfo.Height]; SkipMipmaps(); switch (Format) { case VTexFormat.DXT1: TextureDecompressors.UncompressDXT1(imageInfo, GetDecompressedBuffer(), data, Width, Height); break; case VTexFormat.DXT5: var yCoCg = false; var normalize = false; var invert = false; if (Resource.EditInfo.Structs.ContainsKey(ResourceEditInfo.REDIStruct.SpecialDependencies)) { var specialDeps = (SpecialDependencies)Resource.EditInfo.Structs[ResourceEditInfo.REDIStruct.SpecialDependencies]; yCoCg = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version Image YCoCg Conversion"); normalize = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version Image NormalizeNormals"); invert = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version LegacySource1InvertNormals"); } TextureDecompressors.UncompressDXT5(imageInfo, GetDecompressedBuffer(), data, Width, Height, yCoCg, normalize, invert); break; case VTexFormat.I8: return(TextureDecompressors.ReadI8(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RGBA8888: return(TextureDecompressors.ReadRGBA8888(GetDecompressedBuffer(), Width, Height)); case VTexFormat.R16: return(TextureDecompressors.ReadR16(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RG1616: return(TextureDecompressors.ReadRG1616(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RGBA16161616: TextureDecompressors.ReadRGBA16161616(imageInfo, GetDecompressedBuffer(), data); break; case VTexFormat.R16F: return(TextureDecompressors.ReadR16F(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RG1616F: return(TextureDecompressors.ReadRG1616F(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RGBA16161616F: TextureDecompressors.ReadRGBA16161616F(imageInfo, GetDecompressedBuffer(), data); break; case VTexFormat.R32F: return(TextureDecompressors.ReadR32F(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RG3232F: return(TextureDecompressors.ReadRG3232F(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RGB323232F: return(TextureDecompressors.ReadRGB323232F(GetDecompressedBuffer(), Width, Height)); case VTexFormat.RGBA32323232F: return(TextureDecompressors.ReadRGBA32323232F(GetDecompressedBuffer(), Width, Height)); case VTexFormat.IA88: return(TextureDecompressors.ReadIA88(GetDecompressedBuffer(), Width, Height)); // TODO: Are we sure DXT5 and RGBA8888 are just raw buffers? case VTexFormat.JPEG_DXT5: case VTexFormat.JPEG_RGBA8888: case VTexFormat.PNG_DXT5: case VTexFormat.PNG_RGBA8888: return(ReadBuffer()); case VTexFormat.ETC2: var etc = new Etc.EtcDecoder(); var rewriteMeProperlyPlease = new byte[data.Length]; // TODO etc.DecompressETC2(GetDecompressedTextureAtMipLevel(0), width, height, rewriteMeProperlyPlease); data = rewriteMeProperlyPlease; break; case VTexFormat.ETC2_EAC: var etc2 = new Etc.EtcDecoder(); var rewriteMeProperlyPlease2 = new byte[data.Length]; // TODO etc2.DecompressETC2A8(GetDecompressedTextureAtMipLevel(0), width, height, rewriteMeProperlyPlease2); data = rewriteMeProperlyPlease2; break; default: throw new NotImplementedException(string.Format("Unhandled image type: {0}", Format)); } // pin the managed array so that the GC doesn't move it // TODO: There's probably a better way of handling this with Span<byte> var gcHandle = GCHandle.Alloc(data.ToArray(), GCHandleType.Pinned); // install the pixels with the color type of the pixel data var bitmap = new SKBitmap(); bitmap.InstallPixels(imageInfo, gcHandle.AddrOfPinnedObject(), imageInfo.RowBytes, (address, context) => { gcHandle.Free(); }, null); return(bitmap); }
public SKBitmap GenerateBitmap() { Reader.BaseStream.Position = DataOffset; var width = NonPow2Width > 0 ? NonPow2Width : Width; var height = NonPow2Height > 0 ? NonPow2Height : Height; var imageInfo = new SKImageInfo(width, height, SKColorType.Bgra8888, SKAlphaType.Unpremul); Span <byte> data = new byte[imageInfo.RowBytes * imageInfo.Height]; switch (Format) { case VTexFormat.DXT1: SkipMipmaps(8); TextureDecompressors.UncompressDXT1(imageInfo, Reader, data, Width, Height); break; case VTexFormat.DXT5: var yCoCg = false; var normalize = false; var invert = false; if (Resource.EditInfo.Structs.ContainsKey(ResourceEditInfo.REDIStruct.SpecialDependencies)) { var specialDeps = (SpecialDependencies)Resource.EditInfo.Structs[ResourceEditInfo.REDIStruct.SpecialDependencies]; yCoCg = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version Image YCoCg Conversion"); normalize = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version Image NormalizeNormals"); invert = specialDeps.List.Any(dependancy => dependancy.CompilerIdentifier == "CompileTexture" && dependancy.String == "Texture Compiler Version LegacySource1InvertNormals"); } SkipMipmaps(16); TextureDecompressors.UncompressDXT5(imageInfo, Reader, data, Width, Height, yCoCg, normalize, invert); break; case VTexFormat.I8: SkipMipmaps(1); return(TextureDecompressors.ReadI8(Reader, Width, Height)); case VTexFormat.RGBA8888: SkipMipmaps(4); return(TextureDecompressors.ReadRGBA8888(Reader, Width, Height)); case VTexFormat.R16: SkipMipmaps(2); return(TextureDecompressors.ReadR16(Reader, Width, Height)); case VTexFormat.RG1616: SkipMipmaps(4); return(TextureDecompressors.ReadRG1616(Reader, Width, Height)); case VTexFormat.RGBA16161616: SkipMipmaps(8); TextureDecompressors.ReadRGBA16161616(imageInfo, Reader, data); break; case VTexFormat.R16F: SkipMipmaps(2); return(TextureDecompressors.ReadR16F(Reader, Width, Height)); case VTexFormat.RG1616F: SkipMipmaps(4); return(TextureDecompressors.ReadRG1616F(Reader, Width, Height)); case VTexFormat.RGBA16161616F: SkipMipmaps(8); TextureDecompressors.ReadRGBA16161616F(imageInfo, Reader, data); break; case VTexFormat.R32F: SkipMipmaps(4); return(TextureDecompressors.ReadR32F(Reader, Width, Height)); case VTexFormat.RG3232F: SkipMipmaps(8); return(TextureDecompressors.ReadRG3232F(Reader, Width, Height)); case VTexFormat.RGB323232F: SkipMipmaps(12); return(TextureDecompressors.ReadRGB323232F(Reader, Width, Height)); case VTexFormat.RGBA32323232F: SkipMipmaps(16); return(TextureDecompressors.ReadRGBA32323232F(Reader, Width, Height)); case VTexFormat.IA88: SkipMipmaps(2); return(TextureDecompressors.ReadIA88(Reader, Width, Height)); case VTexFormat.JPG: case VTexFormat.PNG2: case VTexFormat.PNG: return(ReadBuffer()); default: throw new NotImplementedException(string.Format("Unhandled image type: {0}", Format)); } // pin the managed array so that the GC doesn't move it // TODO: There's probably a better way of handling this with Span<byte> var gcHandle = GCHandle.Alloc(data.ToArray(), GCHandleType.Pinned); // install the pixels with the color type of the pixel data var bitmap = new SKBitmap(); bitmap.InstallPixels(imageInfo, gcHandle.AddrOfPinnedObject(), imageInfo.RowBytes, null, delegate { gcHandle.Free(); }, null); return(bitmap); }