// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Processing.Transforms.Processors
{
///
/// Points to a collection of of weights allocated in .
///
internal struct WeightsWindow
{
///
/// The local left index position
///
public int Left;
///
/// The length of the weights window
///
public int Length;
///
/// The index in the destination buffer
///
private readonly int flatStartIndex;
///
/// The buffer containing the weights values.
///
private readonly IBuffer buffer;
///
/// Initializes a new instance of the struct.
///
/// The destination index in the buffer
/// The local left index
/// The span
/// The length of the window
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal WeightsWindow(int index, int left, Buffer2D buffer, int length)
{
this.flatStartIndex = (index * buffer.Width) + left;
this.Left = left;
this.buffer = buffer.Buffer;
this.Length = length;
}
///
/// Gets a reference to the first item of the window.
///
/// The reference to the first item of the window
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref float GetStartReference()
{
Span span = this.buffer.Span;
return ref span[this.flatStartIndex];
}
///
/// Gets the span representing the portion of the that this window covers
///
/// The
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span GetWindowSpan() => this.buffer.Slice(this.flatStartIndex, this.Length);
///
/// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance.
///
/// The input span of vectors
/// The source row position.
/// The weighted sum
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ComputeWeightedRowSum(Span rowSpan, int sourceX)
{
ref float horizontalValues = ref this.GetStartReference();
int left = this.Left;
ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left + sourceX);
// Destination color components
Vector4 result = Vector4.Zero;
for (int i = 0; i < this.Length; i++)
{
float weight = Unsafe.Add(ref horizontalValues, i);
Vector4 v = Unsafe.Add(ref vecPtr, i);
result += v.Premultiply() * weight;
}
return result;
}
///
/// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance.
/// Applies to all input vectors.
///
/// The input span of vectors
/// The source row position.
/// The weighted sum
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ComputeExpandedWeightedRowSum(Span rowSpan, int sourceX)
{
ref float horizontalValues = ref this.GetStartReference();
int left = this.Left;
ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left + sourceX);
// Destination color components
Vector4 result = Vector4.Zero;
for (int i = 0; i < this.Length; i++)
{
float weight = Unsafe.Add(ref horizontalValues, i);
Vector4 v = Unsafe.Add(ref vecPtr, i);
result += v.Premultiply().Expand() * weight;
}
return result.UnPremultiply();
}
///
/// Computes the sum of vectors in 'firstPassPixels' at a row pointed by 'x',
/// weighted by weight values, pointed by this instance.
///
/// The buffer of input vectors in row first order
/// The row position
/// The source column position.
/// The weighted sum
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ComputeWeightedColumnSum(Buffer2D firstPassPixels, int x, int sourceY)
{
ref float verticalValues = ref this.GetStartReference();
int left = this.Left;
// Destination color components
Vector4 result = Vector4.Zero;
for (int i = 0; i < this.Length; i++)
{
float yw = Unsafe.Add(ref verticalValues, i);
int index = left + i + sourceY;
result += firstPassPixels[x, index] * yw;
}
return result.UnPremultiply();
}
}
}