FloodFillChunkCache.cs 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
  2. using PixiEditor.ChangeableDocument.Changeables.Interfaces;
  3. using PixiEditor.ChangeableDocument.Rendering;
  4. using Drawie.Backend.Core;
  5. using Drawie.Backend.Core.Numerics;
  6. using Drawie.Backend.Core.Surfaces;
  7. using Drawie.Backend.Core.Surfaces.ImageData;
  8. using Drawie.Backend.Core.Surfaces.PaintImpl;
  9. using Drawie.Numerics;
  10. namespace PixiEditor.ChangeableDocument.Changes.Drawing.FloodFill;
  11. internal class FloodFillChunkCache : IDisposable
  12. {
  13. private Paint ReplacingPaint { get; } = new Paint() { BlendMode = BlendMode.Src };
  14. private readonly HashSet<Guid>? membersToRender;
  15. private readonly IReadOnlyDocument? document;
  16. private readonly IReadOnlyChunkyImage? image;
  17. private readonly int frame;
  18. private readonly Dictionary<VecI, OneOf<Chunk, EmptyChunk>> acquiredChunks = new();
  19. private ColorSpace processingColorSpace = ColorSpace.CreateSrgbLinear();
  20. public FloodFillChunkCache(IReadOnlyChunkyImage image)
  21. {
  22. this.image = image;
  23. this.processingColorSpace = image.ProcessingColorSpace;
  24. }
  25. public FloodFillChunkCache(HashSet<Guid> membersToRender, IReadOnlyDocument document, int frame)
  26. {
  27. this.membersToRender = membersToRender;
  28. this.document = document;
  29. this.frame = frame;
  30. processingColorSpace = document.ProcessingColorSpace;
  31. }
  32. public bool ChunkExistsInStorage(VecI pos)
  33. {
  34. if (image is not null)
  35. return acquiredChunks.ContainsKey(pos);
  36. return true;
  37. }
  38. public OneOf<Chunk, EmptyChunk> GetChunk(VecI pos)
  39. {
  40. // the chunk was already acquired before, return cached
  41. if (acquiredChunks.TryGetValue(pos, out var foundChunk))
  42. return foundChunk;
  43. // need to get the chunk by merging multiple members
  44. if (image is null)
  45. {
  46. if (document is null || membersToRender is null)
  47. throw new InvalidOperationException();
  48. Chunk chunk = Chunk.Create(processingColorSpace);
  49. chunk.Surface.DrawingSurface.Canvas.Save();
  50. VecI chunkPos = pos * ChunkyImage.FullChunkSize;
  51. chunk.Surface.DrawingSurface.Canvas.Translate(-chunkPos.X, -chunkPos.Y);
  52. document.Renderer.RenderLayers(chunk.Surface.DrawingSurface, membersToRender, frame, ChunkResolution.Full, chunk.Surface.Size);
  53. chunk.Surface.DrawingSurface.Canvas.Restore();
  54. acquiredChunks[pos] = chunk;
  55. return chunk;
  56. }
  57. // there is only a single image, just get the chunk from it
  58. if (!image.LatestOrCommittedChunkExists(pos))
  59. return new EmptyChunk();
  60. Chunk chunkOnImage = Chunk.Create(processingColorSpace, ChunkResolution.Full);
  61. if (!image.DrawMostUpToDateChunkOn(pos, ChunkResolution.Full, chunkOnImage.Surface.DrawingSurface.Canvas, VecI.Zero, ReplacingPaint))
  62. {
  63. chunkOnImage.Dispose();
  64. acquiredChunks[pos] = new EmptyChunk();
  65. return new EmptyChunk();
  66. }
  67. acquiredChunks[pos] = chunkOnImage;
  68. return chunkOnImage;
  69. }
  70. public void Dispose()
  71. {
  72. foreach (var chunk in acquiredChunks.Values.Where(static chunk => chunk.IsT0))
  73. chunk.AsT0.Dispose();
  74. ReplacingPaint.Dispose();
  75. }
  76. }