public static Bc7Block EncodeBlock(RawBlock4X4Rgba32 block, int startingVariation) { bool hasAlpha = block.HasTransparentPixels(); Bc7Block output = new Bc7Block(); Bc7EncodingHelpers.GetInitialUnscaledEndpoints(block, out var ep0, out var ep1); ColorRgba32 scaledEp0 = Bc7EncodingHelpers.ScaleDownEndpoint(ep0, Bc7BlockType.Type6, false, out byte pBit0); ColorRgba32 scaledEp1 = Bc7EncodingHelpers.ScaleDownEndpoint(ep1, Bc7BlockType.Type6, false, out byte pBit1); ReadOnlySpan<int> partitionTable = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const int subset = 0; //Force 255 alpha if fully opaque if (!hasAlpha) { pBit0 = 1; pBit1 = 1; } Bc7EncodingHelpers.OptimizeSubsetEndpointsWithPBit(Bc7BlockType.Type6, block, ref scaledEp0, ref scaledEp1, ref pBit0, ref pBit1, startingVariation, partitionTable, subset, hasAlpha, hasAlpha); ep0 = Bc7EncodingHelpers.ExpandEndpoint(Bc7BlockType.Type6, scaledEp0, pBit0); ep1 = Bc7EncodingHelpers.ExpandEndpoint(Bc7BlockType.Type6, scaledEp1, pBit1); byte[] indices = new byte[16]; Bc7EncodingHelpers.FillSubsetIndices(Bc7BlockType.Type6, block, ep0, ep1, partitionTable, subset, indices); if ((indices[0] & 0b1000) > 0) //If anchor index most significant bit is 1, switch endpoints { var c = scaledEp0; var p = pBit0; scaledEp0 = scaledEp1; pBit0 = pBit1; scaledEp1 = c; pBit1 = p; //redo indices ep0 = Bc7EncodingHelpers.ExpandEndpoint(Bc7BlockType.Type6, scaledEp0, pBit0); ep1 = Bc7EncodingHelpers.ExpandEndpoint(Bc7BlockType.Type6, scaledEp1, pBit1); Bc7EncodingHelpers.FillSubsetIndices(Bc7BlockType.Type6, block, ep0, ep1, partitionTable, subset, indices); } output.PackType6(new[]{ new byte[]{scaledEp0.r, scaledEp0.g, scaledEp0.b, scaledEp0.a}, new byte[]{scaledEp1.r, scaledEp1.g, scaledEp1.b, scaledEp1.a}, }, new[] { pBit0, pBit1 }, indices); return output; }
public static Bc7Block EncodeBlock(RawBlock4X4Rgba32 block, int startingVariation, int bestPartition) { Bc7Block output = new Bc7Block(); const Bc7BlockType type = Bc7BlockType.Type0; if (bestPartition >= 16) { throw new IndexOutOfRangeException("Mode0 only has 16 partitions"); } ColorRgba32[] endpoints = new ColorRgba32[6]; byte[] pBits = new byte[6]; ReadOnlySpan <int> partitionTable = Bc7Block.Subsets3PartitionTable[bestPartition]; byte[] indices = new byte[16]; int[] anchorIndices = new int[] { 0, Bc7Block.Subsets3AnchorIndices2[bestPartition], Bc7Block.Subsets3AnchorIndices3[bestPartition] }; for (int subset = 0; subset < 3; subset++) { Bc7EncodingHelpers.GetInitialUnscaledEndpointsForSubset(block, out var ep0, out var ep1, partitionTable, subset); ColorRgba32 scaledEp0 = Bc7EncodingHelpers.ScaleDownEndpoint(ep0, type, true, out byte pBit0); ColorRgba32 scaledEp1 = Bc7EncodingHelpers.ScaleDownEndpoint(ep1, type, true, out byte pBit1); Bc7EncodingHelpers.OptimizeSubsetEndpointsWithPBit(type, block, ref scaledEp0, ref scaledEp1, ref pBit0, ref pBit1, startingVariation, partitionTable, subset, true, false); ep0 = Bc7EncodingHelpers.ExpandEndpoint(type, scaledEp0, pBit0); ep1 = Bc7EncodingHelpers.ExpandEndpoint(type, scaledEp1, pBit1); Bc7EncodingHelpers.FillSubsetIndices(type, block, ep0, ep1, partitionTable, subset, indices); if ((indices[anchorIndices[subset]] & 0b100) > 0) //If anchor index most significant bit is 1, switch endpoints { var c = scaledEp0; var p = pBit0; scaledEp0 = scaledEp1; pBit0 = pBit1; scaledEp1 = c; pBit1 = p; //redo indices ep0 = Bc7EncodingHelpers.ExpandEndpoint(type, scaledEp0, pBit0); ep1 = Bc7EncodingHelpers.ExpandEndpoint(type, scaledEp1, pBit1); Bc7EncodingHelpers.FillSubsetIndices(type, block, ep0, ep1, partitionTable, subset, indices); } endpoints[subset * 2] = scaledEp0; endpoints[subset * 2 + 1] = scaledEp1; pBits[subset * 2] = pBit0; pBits[subset * 2 + 1] = pBit1; } output.PackType0(bestPartition, new[] { new byte[] { endpoints[0].r, endpoints[0].g, endpoints[0].b }, new byte[] { endpoints[1].r, endpoints[1].g, endpoints[1].b }, new byte[] { endpoints[2].r, endpoints[2].g, endpoints[2].b }, new byte[] { endpoints[3].r, endpoints[3].g, endpoints[3].b }, new byte[] { endpoints[4].r, endpoints[4].g, endpoints[4].b }, new byte[] { endpoints[5].r, endpoints[5].g, endpoints[5].b } }, pBits, indices); return(output); }
public static Bc7Block EncodeBlock(RawBlock4X4Rgba32 block, int startingVariation) { var type = Bc7BlockType.Type4; Span <Bc7Block> outputs = stackalloc Bc7Block[8]; for (int idxMode = 0; idxMode < 2; idxMode++) { for (int rotation = 0; rotation < 4; rotation++) { var rotatedBlock = Bc7EncodingHelpers.RotateBlockColors(block, rotation); Bc7Block output = new Bc7Block(); Bc7EncodingHelpers.GetInitialUnscaledEndpoints(rotatedBlock, out var ep0, out var ep1); ColorRgba32 scaledEp0 = Bc7EncodingHelpers.ScaleDownEndpoint(ep0, type, false, out byte _); ColorRgba32 scaledEp1 = Bc7EncodingHelpers.ScaleDownEndpoint(ep1, type, false, out byte _); byte pBit = 0; //fake pBit Bc7EncodingHelpers.OptimizeSubsetEndpointsWithPBit(type, rotatedBlock, ref scaledEp0, ref scaledEp1, ref pBit, ref pBit, startingVariation, partitionTable, subset, false, true, idxMode); ep0 = Bc7EncodingHelpers.ExpandEndpoint(type, scaledEp0, 0); ep1 = Bc7EncodingHelpers.ExpandEndpoint(type, scaledEp1, 0); byte[] colorIndices = new byte[16]; byte[] alphaIndices = new byte[16]; Bc7EncodingHelpers.FillAlphaColorIndices(type, rotatedBlock, ep0, ep1, colorIndices, alphaIndices, idxMode); bool needsRedo = false; if ((colorIndices[0] & (idxMode == 0 ? 0b10 : 0b100)) > 0) //If anchor index most significant bit is 1, switch endpoints { var c = scaledEp0; var alpha0 = scaledEp0.a; var alpha1 = scaledEp1.a; scaledEp0 = scaledEp1; scaledEp1 = c; scaledEp0.a = alpha0; scaledEp1.a = alpha1; needsRedo = true; } if ((alphaIndices[0] & (idxMode == 0 ? 0b100 : 0b10)) > 0) //If anchor index most significant bit is 1, switch endpoints { var a = scaledEp0.a; scaledEp0.a = scaledEp1.a; scaledEp1.a = a; needsRedo = true; } if (needsRedo) { //redo indices ep0 = Bc7EncodingHelpers.ExpandEndpoint(type, scaledEp0, 0); ep1 = Bc7EncodingHelpers.ExpandEndpoint(type, scaledEp1, 0); Bc7EncodingHelpers.FillAlphaColorIndices(type, rotatedBlock, ep0, ep1, colorIndices, alphaIndices, idxMode); } if (idxMode == 0) { output.PackType4(rotation, (byte)idxMode, new[] { new byte[] { scaledEp0.r, scaledEp0.g, scaledEp0.b }, new byte[] { scaledEp1.r, scaledEp1.g, scaledEp1.b }, }, new[] { scaledEp0.a, scaledEp1.a }, colorIndices, alphaIndices); } else { output.PackType4(rotation, (byte)idxMode, new[] { new byte[] { scaledEp0.r, scaledEp0.g, scaledEp0.b }, new byte[] { scaledEp1.r, scaledEp1.g, scaledEp1.b }, }, new[] { scaledEp0.a, scaledEp1.a }, alphaIndices, colorIndices); } outputs[idxMode * 4 + rotation] = output; } } int bestIndex = 0; float bestError = 0; bool first = true; // Find best out of generated blocks for (int i = 0; i < outputs.Length; i++) { var decoded = outputs[i].Decode(); float error = block.CalculateYCbCrAlphaError(decoded); if (error < bestError || first) { first = false; bestError = error; bestIndex = i; } } return(outputs[bestIndex]); }