Exemple #1
0
    // 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))));
 }
Exemple #5
0
    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);
    }
Exemple #6
0
        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);
     }
 }
Exemple #8
0
    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);
    }
Exemple #9
0
        /// <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));
        }
    }