//
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
namespace ImageSharp.Drawing.Processors
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
///
/// primitive that converts a point in to a color for discovering the fill color based on an implementation
///
/// The pixel format.
///
public abstract class BrushApplicator : IDisposable // disposable will be required if/when there is an ImageBrush
where TColor : struct, IPixel
{
///
/// Initializes a new instance of the class.
///
/// The target.
internal BrushApplicator(PixelAccessor target)
{
this.Target = target;
}
///
/// Gets the destinaion
///
protected PixelAccessor Target { get; }
///
/// Gets the color for a single pixel.
///
/// The x cordinate.
/// The y cordinate.
/// The a that should be applied to the pixel.
internal abstract TColor this[int x, int y] { get; }
///
public abstract void Dispose();
///
/// Applies the opactiy weighting for each pixel in a scanline to the target based on the pattern contained in the brush.
///
/// The a collection of opacity values between 0 and 1 to be merged with the brushed color value before being applied to the target.
/// The number of pixels effected by this scanline.
/// The offset fromthe begining of the opacity data starts.
/// The x position in the target pixel space that the start of the scanline data corresponds to.
/// The y position in the target pixel space that whole scanline corresponds to.
/// scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs.
internal virtual void Apply(float[] scanlineBuffer, int scanlineWidth, int offset, int x, int y)
{
DebugGuard.MustBeGreaterThanOrEqualTo(scanlineBuffer.Length, offset + scanlineWidth, nameof(scanlineWidth));
using (PinnedBuffer buffer = new PinnedBuffer(scanlineBuffer))
{
BufferSpan slice = buffer.Slice(offset);
for (int xPos = 0; xPos < scanlineWidth; xPos++)
{
int targetX = xPos + x;
int targetY = y;
float opacity = slice[xPos];
if (opacity > Constants.Epsilon)
{
Vector4 backgroundVector = this.Target[targetX, targetY].ToVector4();
Vector4 sourceVector = this[targetX, targetY].ToVector4();
Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
TColor packed = default(TColor);
packed.PackFromVector4(finalColor);
this.Target[targetX, targetY] = packed;
}
}
}
}
}
}