using ChunkyImageLib.DataHolders; using PixiEditor.DrawingApi.Core.ColorsImpl; using PixiEditor.DrawingApi.Core.Numerics; using PixiEditor.DrawingApi.Core.Surface; namespace ChunkyImageLib.Operations; internal class ReplaceColorOperation : IDrawOperation { private readonly Color oldColor; private readonly Color newColor; private readonly ColorBounds oldColorBounds; private readonly ulong newColorBits; public bool IgnoreEmptyChunks => true; public ReplaceColorOperation(Color oldColor, Color newColor) { this.oldColor = oldColor; this.newColor = newColor; oldColorBounds = new ColorBounds(oldColor); newColorBits = newColor.ToULong(); } public void DrawOnChunk(Chunk targetChunk, VecI chunkPos) { ReplaceColor(oldColorBounds, newColorBits, targetChunk); } private static unsafe void ReplaceColor(ColorBounds oldColorBounds, ulong newColorBits, Chunk chunk) { int maxThreads = Environment.ProcessorCount; VecI imageSize = chunk.PixelSize; int rowsPerThread = imageSize.Y / maxThreads; using Pixmap pixmap = chunk.Surface.DrawingSurface.PeekPixels(); IntPtr pixels = pixmap.GetPixels(); Half* endOffset = (Half*)(pixels + pixmap.BytesSize); for (Half* i = (Half*)pixels; i < endOffset; i += 4) { if (oldColorBounds.IsWithinBounds(i)) { *(ulong*)i = newColorBits; } } } public AffectedArea FindAffectedArea(VecI imageSize) { RectI rect = new(VecI.Zero, imageSize); return new AffectedArea(OperationHelper.FindChunksTouchingRectangle(rect, ChunkyImage.FullChunkSize), rect); } public void Dispose() { } }