using System; using System.Numerics; using RGB.NET.Core; namespace RGB.NET.Presets.Textures.Sampler; /// /// Represents a sampled that averages multiple byte-data entries. /// public sealed class AverageByteSampler : ISampler { #region Constants private static readonly int INT_VECTOR_LENGTH = Vector.Count; #endregion #region Methods /// public unsafe void Sample(in SamplerInfo info, Span pixelData) { int count = info.Width * info.Height; if (count == 0) return; int dataLength = pixelData.Length; Span sums = stackalloc uint[dataLength]; int elementsPerVector = Vector.Count / dataLength; int valuesPerVector = elementsPerVector * dataLength; if (Vector.IsHardwareAccelerated && (info.Height > 1) && (info.Width >= valuesPerVector) && (dataLength <= Vector.Count)) { int chunks = info.Width / elementsPerVector; Vector sum1 = Vector.Zero; Vector sum2 = Vector.Zero; Vector sum3 = Vector.Zero; Vector sum4 = Vector.Zero; for (int y = 0; y < info.Height; y++) { ReadOnlySpan data = info[y]; fixed (byte* colorPtr = data) { byte* current = colorPtr; for (int i = 0; i < chunks; i++) { Vector bytes = *(Vector*)current; Vector.Widen(bytes, out Vector short1, out Vector short2); Vector.Widen(short1, out Vector int1, out Vector int2); Vector.Widen(short2, out Vector int3, out Vector int4); sum1 = Vector.Add(sum1, int1); sum2 = Vector.Add(sum2, int2); sum3 = Vector.Add(sum3, int3); sum4 = Vector.Add(sum4, int4); current += valuesPerVector; } } int missingElements = data.Length - (chunks * valuesPerVector); int offset = chunks * valuesPerVector; for (int i = 0; i < missingElements; i += dataLength) for (int j = 0; j < sums.Length; j++) sums[j] += data[offset + i + j]; } int value = 0; int sumIndex = 0; for (int j = 0; (j < INT_VECTOR_LENGTH) && (value < valuesPerVector); j++) { sums[sumIndex] += sum1[j]; ++sumIndex; ++value; if (sumIndex >= dataLength) sumIndex = 0; } for (int j = 0; (j < INT_VECTOR_LENGTH) && (value < valuesPerVector); j++) { sums[sumIndex] += sum2[j]; ++sumIndex; ++value; if (sumIndex >= dataLength) sumIndex = 0; } for (int j = 0; (j < INT_VECTOR_LENGTH) && (value < valuesPerVector); j++) { sums[sumIndex] += sum3[j]; ++sumIndex; ++value; if (sumIndex >= dataLength) sumIndex = 0; } for (int j = 0; (j < INT_VECTOR_LENGTH) && (value < valuesPerVector); j++) { sums[sumIndex] += sum4[j]; ++sumIndex; ++value; if (sumIndex >= dataLength) sumIndex = 0; } } else { for (int y = 0; y < info.Height; y++) { ReadOnlySpan data = info[y]; for (int i = 0; i < data.Length; i += dataLength) for (int j = 0; j < sums.Length; j++) sums[j] += data[i + j]; } } float divisor = count * byte.MaxValue; for (int i = 0; i < pixelData.Length; i++) pixelData[i] = (sums[i] / divisor).GetByteValueFromPercentage(); } #endregion }