/// <summary> /// Encodes all cubemap faces and mipmap levels into a Dds file. /// Order is +X, -X, +Y, -Y, +Z, -Z. Back maps to positive Z and front to negative Z. /// </summary> public DdsFile EncodeCubeMapToDds(Image <Rgba32> right, Image <Rgba32> left, Image <Rgba32> top, Image <Rgba32> down, Image <Rgba32> back, Image <Rgba32> front) { DdsFile 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}"); } var(ddsHeader, dxt10Header) = DdsHeader.InitializeCompressed(right.Width, right.Height, compressedEncoder.GetDxgiFormat()); output = new DdsFile(ddsHeader, dxt10Header); if (OutputOptions.ddsBc1WriteAlphaFlag && OutputOptions.format == CompressionFormat.BC1WithAlpha) { output.Header.ddsPixelFormat.dwFlags |= PixelFormatFlags.DDPF_ALPHAPIXELS; } } else { uncompressedEncoder = GetRawEncoder(OutputOptions.format); var ddsHeader = DdsHeader.InitializeUncompressed(right.Width, right.Height, uncompressedEncoder.GetDxgiFormat()); output = new DdsFile(ddsHeader); } uint numMipMaps = (uint)OutputOptions.maxMipMapLevel; if (!OutputOptions.generateMipMaps) { numMipMaps = 1; } for (int f = 0; f < faces.Length; f++) { var mipChain = MipMapper.GenerateMipChain(faces[f], ref numMipMaps); for (int mip = 0; mip < numMipMaps; mip++) { byte[] encoded = null; if (OutputOptions.format.IsCompressedFormat()) { var blocks = ImageToBlocks.ImageTo4X4(mipChain[mip].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[mip].GetPixelSpan()); } if (mip == 0) { output.Faces.Add(new DdsFace((uint)mipChain[mip].Width, (uint)mipChain[mip].Height, (uint)encoded.Length, mipChain.Count)); } output.Faces[f].MipMaps[mip] = new DdsMipMap(encoded, (uint)mipChain[mip].Width, (uint)mipChain[mip].Height); } foreach (var image in mipChain) { image.Dispose(); } } output.Header.dwCaps |= HeaderCaps.DDSCAPS_COMPLEX; output.Header.dwMipMapCount = numMipMaps; if (numMipMaps > 1) { output.Header.dwCaps |= HeaderCaps.DDSCAPS_MIPMAP; } output.Header.dwCaps2 |= HeaderCaps2.DDSCAPS2_CUBEMAP | HeaderCaps2.DDSCAPS2_CUBEMAP_POSITIVEX | HeaderCaps2.DDSCAPS2_CUBEMAP_NEGATIVEX | HeaderCaps2.DDSCAPS2_CUBEMAP_POSITIVEY | HeaderCaps2.DDSCAPS2_CUBEMAP_NEGATIVEY | HeaderCaps2.DDSCAPS2_CUBEMAP_POSITIVEZ | HeaderCaps2.DDSCAPS2_CUBEMAP_NEGATIVEZ; return(output); }
/// <summary> /// Encodes all mipmap levels into a Ktx file. /// </summary> public DdsFile EncodeToDds(Image <Rgba32> inputImage) { DdsFile 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}"); } var(ddsHeader, dxt10Header) = DdsHeader.InitializeCompressed(inputImage.Width, inputImage.Height, compressedEncoder.GetDxgiFormat()); output = new DdsFile(ddsHeader, dxt10Header); if (OutputOptions.ddsBc1WriteAlphaFlag && OutputOptions.format == CompressionFormat.BC1WithAlpha) { output.Header.ddsPixelFormat.dwFlags |= PixelFormatFlags.DDPF_ALPHAPIXELS; } } else { uncompressedEncoder = GetRawEncoder(OutputOptions.format); var ddsHeader = DdsHeader.InitializeUncompressed(inputImage.Width, inputImage.Height, uncompressedEncoder.GetDxgiFormat()); output = new DdsFile(ddsHeader); } uint numMipMaps = (uint)OutputOptions.maxMipMapLevel; if (!OutputOptions.generateMipMaps) { numMipMaps = 1; } var mipChain = MipMapper.GenerateMipChain(inputImage, ref numMipMaps); for (int mip = 0; mip < numMipMaps; mip++) { byte[] encoded = null; if (OutputOptions.format.IsCompressedFormat()) { var blocks = ImageToBlocks.ImageTo4X4(mipChain[mip].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[mip].GetPixelSpan()); } if (mip == 0) { output.Faces.Add(new DdsFace((uint)inputImage.Width, (uint)inputImage.Height, (uint)encoded.Length, (int)numMipMaps)); } output.Faces[0].MipMaps[mip] = new DdsMipMap(encoded, (uint)inputImage.Width, (uint)inputImage.Height); } foreach (var image in mipChain) { image.Dispose(); } output.Header.dwMipMapCount = numMipMaps; if (numMipMaps > 1) { output.Header.dwCaps |= HeaderCaps.DDSCAPS_COMPLEX | HeaderCaps.DDSCAPS_MIPMAP; } return(output); }