// https://github.com/libretro/common-shaders/blob/master/xbr/super-xbr-6p-small-details.cgp // https://github.com/libretro/common-shaders/blob/master/xbr/shaders/super-xbr/super-xbr-small-details-pass0.cg // https://github.com/libretro/common-shaders/blob/master/xbr/shaders/super-xbr/super-xbr-small-details-pass1.cg // https://github.com/libretro/common-shaders/blob/master/xbr/shaders/super-xbr/super-xbr-small-details-pass2.cg private void Scale(ReadOnlySpan <Color16> source, Vector2I sourceSize, Span <Color16> target, Vector2I targetSize) { var source0 = Fixed16.ConvertToReal(source.Elements()).Cast <float, Float4>(); var target0 = SpanExt.Make <Float4>(source.Length); var pass0 = new Passes.Pass0(Configuration, sourceSize, sourceSize); pass0.Pass(source0, target0); var target1 = SpanExt.Make <Float4>(target.Length); var pass1 = new Passes.Pass1(Configuration, sourceSize, targetSize); pass1.Pass(source0, target0, target1); var target2 = SpanExt.Make <Float4>(target.Length); var pass2 = new Passes.Pass2(Configuration, targetSize, targetSize); pass2.Pass(target1, target2); for (int i = 0; i < target2.Length; ++i) { target[i].R = target2[i].R.ScalarToValue16(); target[i].G = target2[i].G.ScalarToValue16(); target[i].B = target2[i].B.ScalarToValue16(); target[i].A = target2[i].A.ScalarToValue16(); } }
internal static bool Encode( ReadOnlySpan <Color8> data, ref TextureFormat format, Vector2I dimensions, bool hasAlpha, bool isPunchthroughAlpha, bool isMasky, bool hasR, bool hasG, bool hasB, out PinnedSpan <byte> result ) { TextureFormat resultFormat = hasAlpha ? TextureFormat.BC3 : TextureFormat.BC1; var resultBytes = SpanExt.MakePinned <byte>(RequiredSize(dimensions, hasAlpha)); var compressionMode = Configuration.Config.Resample.BlockCompression.Quality switch { CompressionQuality.Low => CompressionMode.Normal, CompressionQuality.Medium => CompressionMode.Dither, CompressionQuality.High => CompressionMode.HighQuality, _ => ThrowHelper.ThrowInvalidOperationException <CompressionMode>($"Unknown Quality: '{Configuration.Config.Resample.BlockCompression.Quality}'") }; CompressDxt(resultBytes, data.AsBytes(), dimensions, hasAlpha, compressionMode); result = resultBytes; format = resultFormat; return(true); }
internal static Span <Color8> Extract(ReadOnlySpan <Color8> data, Bounds textureBounds, Bounds spriteBounds, int stride, int block, out Vector2I newExtent) { //if ((bounds.Width % block) != 0 || (bounds.Height % block) != 0) { // throw new ArgumentOutOfRangeException($"Bounds {bounds} are not multiples of block {block}"); //} if (block == 1) { return(Extract(data, textureBounds, spriteBounds, stride, out newExtent)); } var bounds = new Bounds( spriteBounds.Offset, (spriteBounds.Extent / block).Max((1, 1)) ); var result = SpanExt.Make <Color8>(bounds.Area); int startOffset = (bounds.Offset.Y * stride) + bounds.Offset.X; int outOffset = 0; for (int y = 0; y < bounds.Extent.Height; ++y) { int offset = startOffset + ((y * block) * stride); for (int x = 0; x < bounds.Extent.Width; ++x) { result[outOffset++] = data[offset + (x * block)]; } } newExtent = bounds.Extent; return(result); }
public static P3Float Read(ReadOnlySpan <byte> span) { return(new P3Float( SpanExt.GetFloat(span), SpanExt.GetFloat(span.Slice(4)), SpanExt.GetFloat(span.Slice(8)))); }
private static Span <Color16> Apply( Config?config, uint scaleMultiplier, ReadOnlySpan <Color16> sourceData, Vector2I sourceSize, Span <Color16> targetData, Vector2I targetSize ) { if (config is null) { throw new ArgumentNullException(nameof(config)); } if (scaleMultiplier < MinScale || scaleMultiplier > MaxScale || !NumericsExt.IsPow2(scaleMultiplier)) { throw new ArgumentOutOfRangeException(nameof(scaleMultiplier)); } if (sourceSize.X * sourceSize.Y > sourceData.Length) { throw new ArgumentOutOfRangeException(nameof(sourceData)); } var targetSizeCalculated = sourceSize * scaleMultiplier; if (targetSize != targetSizeCalculated) { throw new ArgumentOutOfRangeException(nameof(targetSize)); } if (targetData.IsEmpty) { targetData = SpanExt.MakePinned <Color16>(targetSize.Area); } else { if (targetSize.Area > targetData.Length) { throw new ArgumentOutOfRangeException(nameof(targetData)); } } var scalerInstance = new Scaler( configuration: in config, scaleMultiplier: scaleMultiplier, sourceSize: sourceSize, targetSize: targetSize ); scalerInstance.Scale(sourceData, targetData); return(targetData); }
internal Span <Color16> Execute(ReadOnlySpan <Color16> data) { var buffer1 = SpanExt.Make <Color16>(data.Length); var buffer2 = SpanExt.Make <Color16>(data.Length); DeposterizeH(data, buffer1); DeposterizeV(buffer1, buffer2); //buffer1Data.CopyTo(buffer2Data); for (int pass = 1; pass < Passes; ++pass) { DeposterizeH(buffer2, buffer1); DeposterizeV(buffer1, buffer2); //buffer1Data.CopyTo(buffer2Data); } return(buffer2); }
internal static Span <Color8> Extract(ReadOnlySpan <Color8> data, Bounds textureBounds, Bounds inBounds, int stride, out Vector2I newExtent) { if (inBounds == textureBounds) { newExtent = inBounds.Extent; return(data.ToSpanUnsafe()); } else { var resultData = SpanExt.Make <Color8>(inBounds.Area); int sourceOffset = (textureBounds.Width * inBounds.Top) + inBounds.Left; int destOffset = 0; for (int y = 0; y < inBounds.Height; ++y) { data.Slice(sourceOffset, inBounds.Width).CopyTo(resultData.Slice(destOffset, inBounds.Width)); destOffset += inBounds.Width; sourceOffset += textureBounds.Width; } newExtent = inBounds.Extent; return(resultData); } }
internal static unsafe Span <Color8> ReadFile(Uri path, out Vector2I size) { Console.WriteLine($"Reading {path}"); using var rawImage = Image.FromFile(path.LocalPath); using var image = new Bitmap(rawImage.Width, rawImage.Height, PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(image)) { g.DrawImage(rawImage, 0, 0, rawImage.Width, rawImage.Height); } if (image is null) { throw new NullReferenceException(nameof(image)); } var imageData = image.LockBits(new Rectangle(Point.Empty, image.Size), ImageLockMode.ReadOnly, image.PixelFormat); var imageSpan = SpanExt.Make <Color8>(image.Width * image.Height); var sourceSize = imageData.Height * imageData.Stride; var sourceData = new ReadOnlySpan <byte>(imageData.Scan0.ToPointer(), sourceSize).Cast <Color8>(); int destOffset = 0; int sourceOffset = 0; for (int y = 0; y < imageData.Height; ++y) { sourceData.Slice(sourceOffset, imageData.Width).CopyTo( imageSpan.Slice(destOffset, imageData.Width) ); destOffset += imageData.Width; sourceOffset += (imageData.Stride / sizeof(Color8)); } image.UnlockBits(imageData); size = image.Size; return(imageSpan); }
/// <summary> /// Extracts a color from binary span. /// If the span more than 3 bytes, the 4th byte will be interpreted as alpha. /// Will throw an exception if there is not at least 3 bytes. /// </summary> /// <param name="span">Span to read from</param> /// <param name="binaryType">Format to read the color as</param> /// <returns>Bytes converted to a Color object</returns> public static Color ReadColor(this ReadOnlySpan <byte> span, ColorBinaryType binaryType) { switch (binaryType) { case ColorBinaryType.NoAlpha: return(Color.FromArgb( red: span[0], green: span[1], blue: span[2], alpha: 0)); case ColorBinaryType.Alpha: return(Color.FromArgb( red: span[0], green: span[1], blue: span[2], alpha: span[3])); case ColorBinaryType.NoAlphaFloat: return(Color.FromArgb( red: GetColorByte(SpanExt.GetFloat(span.Slice(0, 4))), green: GetColorByte(SpanExt.GetFloat(span.Slice(4, 4))), blue: GetColorByte(SpanExt.GetFloat(span.Slice(8, 4))), alpha: 0)); case ColorBinaryType.AlphaFloat: return(Color.FromArgb( red: GetColorByte(SpanExt.GetFloat(span.Slice(0, 4))), green: GetColorByte(SpanExt.GetFloat(span.Slice(4, 4))), blue: GetColorByte(SpanExt.GetFloat(span.Slice(8, 4))), alpha: GetColorByte(SpanExt.GetFloat(span.Slice(12, 4))))); default: throw new NotImplementedException(); } }
internal static Span <byte> Decode(ReadOnlySpan <byte> data, Vector2I size, SurfaceFormat format) { Vector2U uSize = size; if (!IsBlockMultiple(uSize)) { throw new ArgumentException($"{nameof(size)}: {uSize} not block multiple"); } switch (format) { case SurfaceFormat.Dxt1: { var blocks = data.Cast <ColorBlock>(); var outData = SpanExt.Make <byte>((int)uSize.Area); var outDataPacked = outData.Cast <uint>(); var widthBlocks = uSize.Width >> 2; uint blockIndex = 0; foreach (var block in blocks) { var index = blockIndex++; var xOffset = (index & widthBlocks - 1) << 2; var yOffset = index / widthBlocks << 2; for (uint y = 0; y < 4; ++y) { var yOffsetInternal = yOffset + y; for (uint x = 0; x < 4; ++x) { var xOffsetInternal = xOffset + x; var offset = yOffsetInternal * uSize.Width + xOffsetInternal; outDataPacked[(int)offset] = block.GetColor((x, y)) | 0xFF000000U; } } } return(outData); } case SurfaceFormat.Dxt3: { var blocks = data.Cast <ColorBlockDxt3>(); var outData = SpanExt.Make <byte>((int)uSize.Area * sizeof(uint)); var outDataPacked = outData.Cast <uint>(); var widthBlocks = uSize.Width >> 2; uint blockIndex = 0; foreach (var block in blocks) { var index = blockIndex++; var xOffset = (index & widthBlocks - 1) << 2; var yOffset = index / widthBlocks << 2; for (uint y = 0; y < 4; ++y) { var yOffsetInternal = yOffset + y; for (uint x = 0; x < 4; ++x) { var xOffsetInternal = xOffset + x; var offset = yOffsetInternal * uSize.Width + xOffsetInternal; outDataPacked[(int)offset] = block.GetColor((x, y)); } } } return(outData); } default: throw new ArgumentOutOfRangeException(nameof(format)); } }