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);
        }
Esempio n. 2
0
        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);
        }