/// <summary> /// Encodes all cubemap faces and mipmap levels into a Ktx file. /// Order is +X, -X, +Y, -Y, +Z, -Z. Back maps to positive Z and front to negative Z. /// </summary> public KtxFile EncodeCubeMapToKtx(Image <Rgba32> right, Image <Rgba32> left, Image <Rgba32> top, Image <Rgba32> down, Image <Rgba32> back, Image <Rgba32> front) { KtxFile output; IBcBlockEncoder compressedEncoder = null; IRawEncoder uncompressedEncoder = null; if (right.Width != left.Width || right.Width != top.Width || right.Width != down.Width || right.Width != back.Width || right.Width != front.Width || right.Height != left.Height || right.Height != top.Height || right.Height != down.Height || right.Height != back.Height || right.Height != front.Height) { throw new ArgumentException("All input images of a cubemap should be the same size."); } Image <Rgba32>[] faces = new[] { right, left, top, down, back, front }; if (OutputOptions.format.IsCompressedFormat()) { compressedEncoder = GetEncoder(OutputOptions.format); if (compressedEncoder == null) { throw new NotSupportedException($"This format is not supported: {OutputOptions.format}"); } output = new KtxFile( KtxHeader.InitializeCompressed(right.Width, right.Height, compressedEncoder.GetInternalFormat(), compressedEncoder.GetBaseInternalFormat())); } else { uncompressedEncoder = GetRawEncoder(OutputOptions.format); output = new KtxFile( KtxHeader.InitializeUncompressed(right.Width, right.Height, uncompressedEncoder.GetGlType(), uncompressedEncoder.GetGlFormat(), uncompressedEncoder.GetGlTypeSize(), uncompressedEncoder.GetInternalFormat(), uncompressedEncoder.GetBaseInternalFormat())); } uint numMipMaps = (uint)OutputOptions.maxMipMapLevel; if (!OutputOptions.generateMipMaps) { numMipMaps = 1; } uint mipLength = MipMapper.CalculateMipChainLength(right.Width, right.Height, numMipMaps); for (uint i = 0; i < mipLength; i++) { output.MipMaps.Add(new KtxMipmap(0, 0, 0, (uint)faces.Length)); } for (int f = 0; f < faces.Length; f++) { var mipChain = MipMapper.GenerateMipChain(faces[f], ref numMipMaps); for (int i = 0; i < numMipMaps; i++) { byte[] encoded = null; if (OutputOptions.format.IsCompressedFormat()) { var blocks = ImageToBlocks.ImageTo4X4(mipChain[i].Frames[0], out int blocksWidth, out int blocksHeight); encoded = compressedEncoder.Encode(blocks, blocksWidth, blocksHeight, OutputOptions.quality, !Debugger.IsAttached && Options.multiThreaded); } else { encoded = uncompressedEncoder.Encode(mipChain[i].GetPixelSpan()); } if (f == 0) { output.MipMaps[i] = new KtxMipmap((uint)encoded.Length, (uint)mipChain[i].Width, (uint)mipChain[i].Height, (uint)faces.Length); } output.MipMaps[i].Faces[f] = new KtxMipFace(encoded, (uint)mipChain[i].Width, (uint)mipChain[i].Height); } foreach (var image in mipChain) { image.Dispose(); } } output.Header.NumberOfFaces = (uint)faces.Length; output.Header.NumberOfMipmapLevels = mipLength; return(output); }
/// <summary> /// Encodes all mipmap levels into a Ktx file. /// </summary> public KtxFile EncodeToKtx(Image <Rgba32> inputImage) { KtxFile output; IBcBlockEncoder compressedEncoder = null; IRawEncoder uncompressedEncoder = null; if (OutputOptions.format.IsCompressedFormat()) { compressedEncoder = GetEncoder(OutputOptions.format); if (compressedEncoder == null) { throw new NotSupportedException($"This format is not supported: {OutputOptions.format}"); } output = new KtxFile( KtxHeader.InitializeCompressed(inputImage.Width, inputImage.Height, compressedEncoder.GetInternalFormat(), compressedEncoder.GetBaseInternalFormat())); } else { uncompressedEncoder = GetRawEncoder(OutputOptions.format); output = new KtxFile( KtxHeader.InitializeUncompressed(inputImage.Width, inputImage.Height, uncompressedEncoder.GetGlType(), uncompressedEncoder.GetGlFormat(), uncompressedEncoder.GetGlTypeSize(), uncompressedEncoder.GetInternalFormat(), uncompressedEncoder.GetBaseInternalFormat())); } uint numMipMaps = (uint)OutputOptions.maxMipMapLevel; if (!OutputOptions.generateMipMaps) { numMipMaps = 1; } var mipChain = MipMapper.GenerateMipChain(inputImage, ref numMipMaps); for (int i = 0; i < numMipMaps; i++) { byte[] encoded = null; if (OutputOptions.format.IsCompressedFormat()) { var blocks = ImageToBlocks.ImageTo4X4(mipChain[i].Frames[0], out int blocksWidth, out int blocksHeight); encoded = compressedEncoder.Encode(blocks, blocksWidth, blocksHeight, OutputOptions.quality, !Debugger.IsAttached && Options.multiThreaded); } else { encoded = uncompressedEncoder.Encode(mipChain[i].GetPixelSpan()); } output.MipMaps.Add(new KtxMipmap((uint)encoded.Length, (uint)inputImage.Width, (uint)inputImage.Height, 1)); output.MipMaps[i].Faces[0] = new KtxMipFace(encoded, (uint)inputImage.Width, (uint)inputImage.Height); } foreach (var image in mipChain) { image.Dispose(); } output.Header.NumberOfFaces = 1; output.Header.NumberOfMipmapLevels = numMipMaps; return(output); }