|
@@ -1,4 +1,5 @@
|
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.ComponentModel.DataAnnotations;
|
|
|
|
|
+using System.Diagnostics;
|
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.CompilerServices;
|
|
|
using ChunkyImageLib.DataHolders;
|
|
using ChunkyImageLib.DataHolders;
|
|
|
using ChunkyImageLib.Operations;
|
|
using ChunkyImageLib.Operations;
|
|
@@ -6,6 +7,7 @@ using OneOf;
|
|
|
using OneOf.Types;
|
|
using OneOf.Types;
|
|
|
using PixiEditor.Common;
|
|
using PixiEditor.Common;
|
|
|
using Drawie.Backend.Core;
|
|
using Drawie.Backend.Core;
|
|
|
|
|
+using Drawie.Backend.Core.Bridge;
|
|
|
using Drawie.Backend.Core.ColorsImpl;
|
|
using Drawie.Backend.Core.ColorsImpl;
|
|
|
using Drawie.Backend.Core.ColorsImpl.Paintables;
|
|
using Drawie.Backend.Core.ColorsImpl.Paintables;
|
|
|
using Drawie.Backend.Core.Numerics;
|
|
using Drawie.Backend.Core.Numerics;
|
|
@@ -193,7 +195,8 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
/// Finds the precise bounds in <paramref name="suggestedResolution"/>. If there are no chunks rendered for that resolution, full res chunks are used instead.
|
|
/// Finds the precise bounds in <paramref name="suggestedResolution"/>. If there are no chunks rendered for that resolution, full res chunks are used instead.
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
/// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
/// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
|
- public RectI? FindTightCommittedBounds(ChunkResolution suggestedResolution = ChunkResolution.Full, bool fallbackToChunkAligned = false)
|
|
|
|
|
|
|
+ public RectI? FindTightCommittedBounds(ChunkResolution suggestedResolution = ChunkResolution.Full,
|
|
|
|
|
+ bool fallbackToChunkAligned = false)
|
|
|
{
|
|
{
|
|
|
lock (lockObject)
|
|
lock (lockObject)
|
|
|
{
|
|
{
|
|
@@ -268,10 +271,10 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
return FindTightCommittedBounds(suggestedResolution, fallbackToChunkAligned);
|
|
return FindTightCommittedBounds(suggestedResolution, fallbackToChunkAligned);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /*if (lastLatestBoundsCacheHash == GetCacheHash())
|
|
|
|
|
|
|
+ if (lastLatestBoundsCacheHash == GetCacheHash())
|
|
|
{
|
|
{
|
|
|
return cachedPreciseLatestBounds;
|
|
return cachedPreciseLatestBounds;
|
|
|
- }*/
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
var chunkSize = suggestedResolution.PixelSize();
|
|
var chunkSize = suggestedResolution.PixelSize();
|
|
|
var multiplier = suggestedResolution.Multiplier();
|
|
var multiplier = suggestedResolution.Multiplier();
|
|
@@ -381,7 +384,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
var image = GetCommittedChunk(chunk, ChunkResolution.Full);
|
|
var image = GetCommittedChunk(chunk, ChunkResolution.Full);
|
|
|
if (image is null)
|
|
if (image is null)
|
|
|
continue;
|
|
continue;
|
|
|
- output.EnqueueDrawImage(chunk * FullChunkSize, image.Surface);
|
|
|
|
|
|
|
+ output.EnqueueDrawTexture(chunk * FullChunkSize, image.Surface);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
output.CommitChanges();
|
|
output.CommitChanges();
|
|
@@ -454,6 +457,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
|
|
|
|
|
// something is queued, blend mode is not Src so we have to do merging
|
|
// something is queued, blend mode is not Src so we have to do merging
|
|
|
{
|
|
{
|
|
|
|
|
+ using var ctx = DrawingBackendApi.Current.RenderingDispatcher.EnsureContext();
|
|
|
Chunk? committedChunk = MaybeGetCommittedChunk(chunkPos, ChunkResolution.Full);
|
|
Chunk? committedChunk = MaybeGetCommittedChunk(chunkPos, ChunkResolution.Full);
|
|
|
Chunk? latestChunk = GetLatestChunk(chunkPos, ChunkResolution.Full);
|
|
Chunk? latestChunk = GetLatestChunk(chunkPos, ChunkResolution.Full);
|
|
|
Color committedColor = committedChunk is null
|
|
Color committedColor = committedChunk is null
|
|
@@ -467,8 +471,8 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
using Chunk tempChunk = Chunk.Create(ProcessingColorSpace, ChunkResolution.Eighth);
|
|
using Chunk tempChunk = Chunk.Create(ProcessingColorSpace, ChunkResolution.Eighth);
|
|
|
using Paint committedPaint = new Paint() { Color = committedColor, BlendMode = BlendMode.Src };
|
|
using Paint committedPaint = new Paint() { Color = committedColor, BlendMode = BlendMode.Src };
|
|
|
using Paint latestPaint = new Paint() { Color = latestColor, BlendMode = this.blendMode };
|
|
using Paint latestPaint = new Paint() { Color = latestColor, BlendMode = this.blendMode };
|
|
|
- tempChunk.Surface.DrawingSurface.Canvas.DrawPixel(VecI.Zero, committedPaint);
|
|
|
|
|
- tempChunk.Surface.DrawingSurface.Canvas.DrawPixel(VecI.Zero, latestPaint);
|
|
|
|
|
|
|
+ tempChunk.Surface.DrawingSurface.Canvas.DrawRect(new RectD(VecI.Zero, new VecD(1)), committedPaint);
|
|
|
|
|
+ tempChunk.Surface.DrawingSurface.Canvas.DrawRect(new RectD(VecI.Zero, new VecI(1)), latestPaint);
|
|
|
return tempChunk.Surface.GetSrgbPixel(VecI.Zero);
|
|
return tempChunk.Surface.GetSrgbPixel(VecI.Zero);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -478,7 +482,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
/// True if the chunk existed and was drawn, otherwise false
|
|
/// True if the chunk existed and was drawn, otherwise false
|
|
|
/// </returns>
|
|
/// </returns>
|
|
|
/// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
/// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
|
- public bool DrawMostUpToDateChunkOn(VecI chunkPos, ChunkResolution resolution, DrawingSurface surface, VecD pos,
|
|
|
|
|
|
|
+ public bool DrawMostUpToDateChunkOn(VecI chunkPos, ChunkResolution resolution, Canvas surface, VecD pos,
|
|
|
Paint? paint = null, SamplingOptions? samplingOptions = null)
|
|
Paint? paint = null, SamplingOptions? samplingOptions = null)
|
|
|
{
|
|
{
|
|
|
lock (lockObject)
|
|
lock (lockObject)
|
|
@@ -520,6 +524,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ using var ctx = DrawingBackendApi.Current.RenderingDispatcher.EnsureContext();
|
|
|
// combine with committed and then draw
|
|
// combine with committed and then draw
|
|
|
using var tempChunk = Chunk.Create(ProcessingColorSpace, resolution);
|
|
using var tempChunk = Chunk.Create(ProcessingColorSpace, resolution);
|
|
|
tempChunk.Surface.DrawingSurface.Canvas.DrawSurface(committedChunk.Surface.DrawingSurface, 0, 0,
|
|
tempChunk.Surface.DrawingSurface.Canvas.DrawSurface(committedChunk.Surface.DrawingSurface, 0, 0,
|
|
@@ -535,6 +540,66 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ public bool DrawCachedMostUpToDateChunkOn(VecI chunkPos, ChunkResolution resolution, Canvas surface,
|
|
|
|
|
+ VecD pos,
|
|
|
|
|
+ Paint? paint = null, SamplingOptions? sampling = null)
|
|
|
|
|
+ {
|
|
|
|
|
+ lock (lockObject)
|
|
|
|
|
+ {
|
|
|
|
|
+ ThrowIfDisposed();
|
|
|
|
|
+ OneOf<None, EmptyChunk, Chunk> latestChunk;
|
|
|
|
|
+ {
|
|
|
|
|
+ var chunk = MaybeGetLatestChunk(chunkPos, resolution);
|
|
|
|
|
+ if (latestChunksData[resolution].TryGetValue(chunkPos, out var chunkData) && chunkData.IsDeleted)
|
|
|
|
|
+ {
|
|
|
|
|
+ latestChunk = new EmptyChunk();
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ latestChunk = chunk is null ? new None() : chunk;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var committedChunk = GetCommittedChunk(chunkPos, resolution);
|
|
|
|
|
+
|
|
|
|
|
+ // draw committed directly
|
|
|
|
|
+ if (latestChunk.IsT0 || latestChunk.IsT1 && committedChunk is not null && blendMode != BlendMode.Src)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (committedChunk is null)
|
|
|
|
|
+ return false;
|
|
|
|
|
+ committedChunk.DrawChunkOn(surface, pos, paint, sampling);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // no need to combine with committed, draw directly
|
|
|
|
|
+ if (blendMode == BlendMode.Src || committedChunk is null)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (latestChunk.IsT2)
|
|
|
|
|
+ {
|
|
|
|
|
+ latestChunk.AsT2.DrawChunkOn(surface, pos, paint, sampling);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ using var ctx = DrawingBackendApi.Current.RenderingDispatcher.EnsureContext();
|
|
|
|
|
+
|
|
|
|
|
+ // combine with committed and then draw
|
|
|
|
|
+ using var tempChunk = Chunk.Create(ProcessingColorSpace, resolution);
|
|
|
|
|
+ tempChunk.Surface.DrawingSurface.Canvas.DrawSurface(committedChunk.Surface.DrawingSurface, 0, 0,
|
|
|
|
|
+ ReplacingPaint);
|
|
|
|
|
+ blendModePaint.BlendMode = blendMode;
|
|
|
|
|
+ tempChunk.Surface.DrawingSurface.Canvas.DrawSurface(latestChunk.AsT2.Surface.DrawingSurface, 0, 0,
|
|
|
|
|
+ blendModePaint);
|
|
|
|
|
+ if (lockTransparency)
|
|
|
|
|
+ OperationHelper.ClampAlpha(tempChunk.Surface.DrawingSurface, committedChunk.Surface.DrawingSurface);
|
|
|
|
|
+ tempChunk.DrawChunkOn(surface, pos, paint, sampling);
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
/// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
|
public bool LatestOrCommittedChunkExists(VecI chunkPos)
|
|
public bool LatestOrCommittedChunkExists(VecI chunkPos)
|
|
|
{
|
|
{
|
|
@@ -571,7 +636,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
/// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
|
- public bool DrawCommittedChunkOn(VecI chunkPos, ChunkResolution resolution, DrawingSurface surface, VecD pos,
|
|
|
|
|
|
|
+ public bool DrawCommittedChunkOn(VecI chunkPos, ChunkResolution resolution, Canvas surface, VecD pos,
|
|
|
Paint? paint = null, SamplingOptions? samplingOptions = null)
|
|
Paint? paint = null, SamplingOptions? samplingOptions = null)
|
|
|
{
|
|
{
|
|
|
lock (lockObject)
|
|
lock (lockObject)
|
|
@@ -856,6 +921,20 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /// <param name="customBounds">Bounds used for affected chunks, will be computed from path in O(n) if null is passed</param>
|
|
|
|
|
+ /// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
|
|
|
+ public void EnqueueDrawPath(VectorPath path, Paintable paintable, float strokeWidth, StrokeCap strokeCap,
|
|
|
|
|
+ BlendMode blendMode, PaintStyle style, bool antiAliasing, RectI? customBounds = null)
|
|
|
|
|
+ {
|
|
|
|
|
+ lock (lockObject)
|
|
|
|
|
+ {
|
|
|
|
|
+ ThrowIfDisposed();
|
|
|
|
|
+ PathOperation operation = new(path, paintable, strokeWidth, strokeCap, blendMode, style, antiAliasing,
|
|
|
|
|
+ customBounds);
|
|
|
|
|
+ EnqueueOperation(operation);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
/// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
|
public void EnqueueDrawBresenhamLine(VecI from, VecI to, Paintable paintable, BlendMode blendMode)
|
|
public void EnqueueDrawBresenhamLine(VecI from, VecI to, Paintable paintable, BlendMode blendMode)
|
|
|
{
|
|
{
|
|
@@ -911,17 +990,6 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
|
|
|
- public void EnqueueDrawPixel(VecI pos, PixelProcessor pixelProcessor, BlendMode blendMode)
|
|
|
|
|
- {
|
|
|
|
|
- lock (lockObject)
|
|
|
|
|
- {
|
|
|
|
|
- ThrowIfDisposed();
|
|
|
|
|
- PixelOperation operation = new(pos, pixelProcessor, GetCommittedPixel, blendMode);
|
|
|
|
|
- EnqueueOperation(operation);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
/// <exception cref="ObjectDisposedException">This image is disposed</exception>
|
|
|
public void EnqueueDrawCommitedChunkyImage(VecI pos, ChunkyImage image, bool flipHor = false, bool flipVer = false)
|
|
public void EnqueueDrawCommitedChunkyImage(VecI pos, ChunkyImage image, bool flipHor = false, bool flipVer = false)
|
|
|
{
|
|
{
|
|
@@ -1069,6 +1137,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
{
|
|
{
|
|
|
lock (lockObject)
|
|
lock (lockObject)
|
|
|
{
|
|
{
|
|
|
|
|
+ using var ctx = DrawingBackendApi.Current.RenderingDispatcher.EnsureContext();
|
|
|
ThrowIfDisposed();
|
|
ThrowIfDisposed();
|
|
|
var affectedArea = FindAffectedArea();
|
|
var affectedArea = FindAffectedArea();
|
|
|
|
|
|
|
@@ -1159,6 +1228,8 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ using var ctx = DrawingBackendApi.Current.RenderingDispatcher.EnsureContext();
|
|
|
|
|
+
|
|
|
//blend
|
|
//blend
|
|
|
blendModePaint.BlendMode = blendMode;
|
|
blendModePaint.BlendMode = blendMode;
|
|
|
if (lockTransparency)
|
|
if (lockTransparency)
|
|
@@ -1238,6 +1309,28 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ public Dictionary<VecI, Surface> CloneAllCommitedNonEmptyChunks()
|
|
|
|
|
+ {
|
|
|
|
|
+ lock (lockObject)
|
|
|
|
|
+ {
|
|
|
|
|
+ ThrowIfDisposed();
|
|
|
|
|
+ using var ctx = DrawingBackendApi.Current.RenderingDispatcher.EnsureContext();
|
|
|
|
|
+ var dict = new Dictionary<VecI, Surface>();
|
|
|
|
|
+ foreach (var (pos, chunk) in committedChunks[ChunkResolution.Full])
|
|
|
|
|
+ {
|
|
|
|
|
+ if (chunk.FindPreciseBounds().HasValue)
|
|
|
|
|
+ {
|
|
|
|
|
+ var surf = new Surface(chunk.Surface.ImageInfo);
|
|
|
|
|
+ surf.DrawingSurface.Canvas.DrawSurface(chunk.Surface.DrawingSurface, 0, 0);
|
|
|
|
|
+ dict[pos] = surf;
|
|
|
|
|
+ surf.DrawingSurface.Flush();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return dict;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/// <returns>
|
|
/// <returns>
|
|
|
/// Chunks affected by operations that haven't been committed yet
|
|
/// Chunks affected by operations that haven't been committed yet
|
|
|
/// </returns>
|
|
/// </returns>
|
|
@@ -1345,7 +1438,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
{
|
|
{
|
|
|
if (mask.CommittedChunkExists(chunkPos))
|
|
if (mask.CommittedChunkExists(chunkPos))
|
|
|
{
|
|
{
|
|
|
- mask.DrawCommittedChunkOn(chunkPos, resolution, intersection.Surface.DrawingSurface, VecI.Zero,
|
|
|
|
|
|
|
+ mask.DrawCommittedChunkOn(chunkPos, resolution, intersection.Surface.DrawingSurface.Canvas, VecI.Zero,
|
|
|
ClippingPaint);
|
|
ClippingPaint);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
@@ -1373,6 +1466,8 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
if (operation is ClearOperation)
|
|
if (operation is ClearOperation)
|
|
|
return true;
|
|
return true;
|
|
|
|
|
|
|
|
|
|
+ using var ctx = DrawingBackendApi.Current.RenderingDispatcher.EnsureContext();
|
|
|
|
|
+
|
|
|
if (operation is IDrawOperation chunkOperation)
|
|
if (operation is IDrawOperation chunkOperation)
|
|
|
{
|
|
{
|
|
|
if (combinedRasterClips.IsT1) // Nothing is visible
|
|
if (combinedRasterClips.IsT1) // Nothing is visible
|
|
@@ -1392,14 +1487,14 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
var clip = combinedRasterClips.AsT2;
|
|
var clip = combinedRasterClips.AsT2;
|
|
|
|
|
|
|
|
using var tempChunk = Chunk.Create(ProcessingColorSpace, targetChunk.Resolution);
|
|
using var tempChunk = Chunk.Create(ProcessingColorSpace, targetChunk.Resolution);
|
|
|
- targetChunk.DrawChunkOn(tempChunk.Surface.DrawingSurface, VecI.Zero, ReplacingPaint);
|
|
|
|
|
|
|
+ targetChunk.DrawChunkOn(tempChunk.Surface.DrawingSurface.Canvas, VecI.Zero, ReplacingPaint);
|
|
|
|
|
|
|
|
CallDrawWithClip(chunkOperation, operationAffectedArea.GlobalArea, tempChunk, resolution, chunkPos);
|
|
CallDrawWithClip(chunkOperation, operationAffectedArea.GlobalArea, tempChunk, resolution, chunkPos);
|
|
|
|
|
|
|
|
- clip.DrawChunkOn(tempChunk.Surface.DrawingSurface, VecI.Zero, ClippingPaint);
|
|
|
|
|
- clip.DrawChunkOn(targetChunk.Surface.DrawingSurface, VecI.Zero, InverseClippingPaint);
|
|
|
|
|
|
|
+ clip.DrawChunkOn(tempChunk.Surface.DrawingSurface.Canvas, VecI.Zero, ClippingPaint);
|
|
|
|
|
+ clip.DrawChunkOn(targetChunk.Surface.DrawingSurface.Canvas, VecI.Zero, InverseClippingPaint);
|
|
|
|
|
|
|
|
- tempChunk.DrawChunkOn(targetChunk.Surface.DrawingSurface, VecI.Zero, AddingPaint);
|
|
|
|
|
|
|
+ tempChunk.DrawChunkOn(targetChunk.Surface.DrawingSurface.Canvas, VecI.Zero, AddingPaint);
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1498,6 +1593,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
private Chunk GetOrCreateCommittedChunk(VecI chunkPos, ChunkResolution resolution)
|
|
private Chunk GetOrCreateCommittedChunk(VecI chunkPos, ChunkResolution resolution)
|
|
|
{
|
|
{
|
|
|
|
|
+ using var ctx = DrawingBackendApi.Current.RenderingDispatcher.EnsureContext();
|
|
|
// committed chunk of the same resolution exists
|
|
// committed chunk of the same resolution exists
|
|
|
Chunk? targetChunk = MaybeGetCommittedChunk(chunkPos, resolution);
|
|
Chunk? targetChunk = MaybeGetCommittedChunk(chunkPos, resolution);
|
|
|
if (targetChunk is not null)
|
|
if (targetChunk is not null)
|
|
@@ -1519,7 +1615,8 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
newChunk.Surface.DrawingSurface.Canvas.Save();
|
|
newChunk.Surface.DrawingSurface.Canvas.Save();
|
|
|
newChunk.Surface.DrawingSurface.Canvas.Scale((float)resolution.Multiplier());
|
|
newChunk.Surface.DrawingSurface.Canvas.Scale((float)resolution.Multiplier());
|
|
|
|
|
|
|
|
- newChunk.Surface.DrawingSurface.Canvas.DrawSurface(existingFullResChunk.Surface.DrawingSurface, 0, 0,
|
|
|
|
|
|
|
+ using var snapshot = existingFullResChunk.Surface.DrawingSurface.Snapshot();
|
|
|
|
|
+ newChunk.Surface.DrawingSurface.Canvas.DrawImage(snapshot, 0, 0, SamplingOptions.Bilinear,
|
|
|
SmoothReplacingPaint);
|
|
SmoothReplacingPaint);
|
|
|
newChunk.Surface.DrawingSurface.Canvas.Restore();
|
|
newChunk.Surface.DrawingSurface.Canvas.Restore();
|
|
|
committedChunks[resolution][chunkPos] = newChunk;
|
|
committedChunks[resolution][chunkPos] = newChunk;
|
|
@@ -1540,6 +1637,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
private Chunk GetOrCreateLatestChunk(VecI chunkPos, ChunkResolution resolution)
|
|
private Chunk GetOrCreateLatestChunk(VecI chunkPos, ChunkResolution resolution)
|
|
|
{
|
|
{
|
|
|
|
|
+ using var ctx = DrawingBackendApi.Current.RenderingDispatcher.EnsureContext();
|
|
|
// latest chunk exists
|
|
// latest chunk exists
|
|
|
Chunk? targetChunk = MaybeGetLatestChunk(chunkPos, resolution);
|
|
Chunk? targetChunk = MaybeGetLatestChunk(chunkPos, resolution);
|
|
|
if (targetChunk is not null)
|
|
if (targetChunk is not null)
|