public static Bc7Block EncodeBlock(RawBlock4X4Rgba32 rawBlock) { bool hasAlpha = rawBlock.HasTransparentPixels(); var indexBlock2 = CreateClusterIndexBlock(rawBlock, out int clusters2, 2); var indexBlock3 = CreateClusterIndexBlock(rawBlock, out int clusters3, 3); if (clusters2 < 2) { clusters2 = clusters3; indexBlock2 = indexBlock3; } int[] best2SubsetPartitions = Bc7EncodingHelpers.Rank2SubsetPartitions(indexBlock2, clusters2); int[] best3SubsetPartitions = Bc7EncodingHelpers.Rank3SubsetPartitions(indexBlock3, clusters3); float bestError = 99999; Bc7Block best = new Bc7Block(); int tries = 0; foreach (Bc7Block block in TryMethods(rawBlock, best2SubsetPartitions, best3SubsetPartitions, hasAlpha)) { var decoded = block.Decode(); float error = rawBlock.CalculateYCbCrAlphaError(decoded); tries++; if (error < bestError) { best = block; bestError = error; } if (error < errorThreshold || tries > maxTries) { break; } } return(best); }
public static Bc7Block EncodeBlock(RawBlock4X4Rgba32 block, int startingVariation) { var type = Bc7BlockType.Type5; Span <Bc7Block> outputs = stackalloc Bc7Block[4]; 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); 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); bool needsRedo = false; if ((colorIndices[0] & 0b10) > 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] & 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); } output.PackType5(rotation, new[] { new byte[] { scaledEp0.r, scaledEp0.g, scaledEp0.b }, new byte[] { scaledEp1.r, scaledEp1.g, scaledEp1.b }, }, new[] { scaledEp0.a, scaledEp1.a }, colorIndices, alphaIndices); outputs[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]); }
public static Bc7Block EncodeBlock(RawBlock4X4Rgba32 block, int startingVariation, int bestPartition) { Bc7Block output = new Bc7Block(); const Bc7BlockType type = Bc7BlockType.Type2; ColorRgba32[] endpoints = new ColorRgba32[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 _); ColorRgba32 scaledEp1 = Bc7EncodingHelpers.ScaleDownEndpoint(ep1, type, true, out byte _); byte pBit = 0; Bc7EncodingHelpers.OptimizeSubsetEndpointsWithPBit(type, block, ref scaledEp0, ref scaledEp1, ref pBit, ref pBit, startingVariation, partitionTable, subset, false, false); ep0 = Bc7EncodingHelpers.ExpandEndpoint(type, scaledEp0, 0); ep1 = Bc7EncodingHelpers.ExpandEndpoint(type, scaledEp1, 0); Bc7EncodingHelpers.FillSubsetIndices(type, block, ep0, ep1, partitionTable, subset, indices); if ((indices[anchorIndices[subset]] & 0b10) > 0) //If anchor index most significant bit is 1, switch endpoints { var c = scaledEp0; scaledEp0 = scaledEp1; scaledEp1 = c; //redo indices ep0 = Bc7EncodingHelpers.ExpandEndpoint(type, scaledEp0, 0); ep1 = Bc7EncodingHelpers.ExpandEndpoint(type, scaledEp1, 0); Bc7EncodingHelpers.FillSubsetIndices(type, block, ep0, ep1, partitionTable, subset, indices); } endpoints[subset * 2] = scaledEp0; endpoints[subset * 2 + 1] = scaledEp1; } output.PackType2(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 } }, indices); return(output); }
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; }