ChunkyImageOperation.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. using ChunkyImageLib.DataHolders;
  2. using PixiEditor.DrawingApi.Core.Numerics;
  3. using SkiaSharp;
  4. namespace ChunkyImageLib.Operations;
  5. internal class ChunkyImageOperation : IDrawOperation
  6. {
  7. private readonly ChunkyImage imageToDraw;
  8. private readonly VecI pos;
  9. private readonly bool mirrorHorizontal;
  10. private readonly bool mirrorVertical;
  11. public bool IgnoreEmptyChunks => false;
  12. public ChunkyImageOperation(ChunkyImage imageToDraw, VecI pos, bool mirrorHorizontal, bool mirrorVertical)
  13. {
  14. this.imageToDraw = imageToDraw;
  15. this.pos = pos;
  16. this.mirrorHorizontal = mirrorHorizontal;
  17. this.mirrorVertical = mirrorVertical;
  18. }
  19. public void DrawOnChunk(Chunk chunk, VecI chunkPos)
  20. {
  21. chunk.Surface.DrawingSurface.Canvas.Save();
  22. {
  23. VecI pixelPos = chunkPos * ChunkyImage.FullChunkSize;
  24. VecI topLeftImageCorner = GetTopLeft();
  25. SKRect clippingRect = SKRect.Create(
  26. OperationHelper.ConvertForResolution(topLeftImageCorner - pixelPos, chunk.Resolution),
  27. OperationHelper.ConvertForResolution(imageToDraw.CommittedSize, chunk.Resolution));
  28. chunk.Surface.DrawingSurface.Canvas.ClipRect(clippingRect);
  29. }
  30. VecI chunkPixelCenter = chunkPos * ChunkyImage.FullChunkSize;
  31. chunkPixelCenter.X += ChunkyImage.FullChunkSize / 2;
  32. chunkPixelCenter.Y += ChunkyImage.FullChunkSize / 2;
  33. VecI chunkCenterOnImage = chunkPixelCenter - pos;
  34. VecI chunkSize = chunk.PixelSize;
  35. if (mirrorHorizontal)
  36. {
  37. chunk.Surface.DrawingSurface.Canvas.Scale(-1, 1, chunkSize.X / 2f, chunkSize.Y / 2f);
  38. chunkCenterOnImage.X = -chunkCenterOnImage.X;
  39. }
  40. if (mirrorVertical)
  41. {
  42. chunk.Surface.DrawingSurface.Canvas.Scale(1, -1, chunkSize.X / 2f, chunkSize.Y / 2f);
  43. chunkCenterOnImage.Y = -chunkCenterOnImage.Y;
  44. }
  45. VecI halfChunk = new(ChunkyImage.FullChunkSize / 2, ChunkyImage.FullChunkSize / 2);
  46. VecI topLeft = OperationHelper.GetChunkPos(chunkCenterOnImage - halfChunk, ChunkyImage.FullChunkSize);
  47. VecI topRight = OperationHelper.GetChunkPos(
  48. new VecI(chunkCenterOnImage.X + halfChunk.X, chunkCenterOnImage.Y - halfChunk.Y), ChunkyImage.FullChunkSize);
  49. VecI bottomRight = OperationHelper.GetChunkPos(chunkCenterOnImage + halfChunk, ChunkyImage.FullChunkSize);
  50. VecI bottomLeft = OperationHelper.GetChunkPos(
  51. new VecI(chunkCenterOnImage.X - halfChunk.X, chunkCenterOnImage.Y + halfChunk.Y), ChunkyImage.FullChunkSize);
  52. imageToDraw.DrawCommittedChunkOn(
  53. topLeft,
  54. chunk.Resolution,
  55. chunk.Surface.DrawingSurface,
  56. (VecI)((topLeft * ChunkyImage.FullChunkSize - chunkCenterOnImage).Add(ChunkyImage.FullChunkSize / 2) * chunk.Resolution.Multiplier()));
  57. VecI gridShift = pos % ChunkyImage.FullChunkSize;
  58. if (gridShift.X != 0)
  59. {
  60. imageToDraw.DrawCommittedChunkOn(
  61. topRight,
  62. chunk.Resolution,
  63. chunk.Surface.DrawingSurface,
  64. (VecI)((topRight * ChunkyImage.FullChunkSize - chunkCenterOnImage).Add(ChunkyImage.FullChunkSize / 2) * chunk.Resolution.Multiplier()));
  65. }
  66. if (gridShift.Y != 0)
  67. {
  68. imageToDraw.DrawCommittedChunkOn(
  69. bottomLeft,
  70. chunk.Resolution,
  71. chunk.Surface.DrawingSurface,
  72. (VecI)((bottomLeft * ChunkyImage.FullChunkSize - chunkCenterOnImage).Add(ChunkyImage.FullChunkSize / 2) * chunk.Resolution.Multiplier()));
  73. }
  74. if (gridShift.X != 0 && gridShift.Y != 0)
  75. {
  76. imageToDraw.DrawCommittedChunkOn(
  77. bottomRight,
  78. chunk.Resolution,
  79. chunk.Surface.DrawingSurface,
  80. (VecI)((bottomRight * ChunkyImage.FullChunkSize - chunkCenterOnImage).Add(ChunkyImage.FullChunkSize / 2) * chunk.Resolution.Multiplier()));
  81. }
  82. chunk.Surface.DrawingSurface.Canvas.Restore();
  83. }
  84. public HashSet<VecI> FindAffectedChunks(VecI imageSize)
  85. {
  86. return OperationHelper.FindChunksTouchingRectangle(new(GetTopLeft(), imageToDraw.CommittedSize), ChunkyImage.FullChunkSize);
  87. }
  88. private VecI GetTopLeft()
  89. {
  90. VecI topLeft = pos;
  91. if (mirrorHorizontal)
  92. topLeft.X -= imageToDraw.CommittedSize.X;
  93. if (mirrorVertical)
  94. topLeft.Y -= imageToDraw.CommittedSize.Y;
  95. return topLeft;
  96. }
  97. public IDrawOperation AsMirrored(int? verAxisX, int? horAxisY)
  98. {
  99. var newPos = pos;
  100. if (verAxisX is not null)
  101. newPos = newPos.ReflectX((int)verAxisX);
  102. if (horAxisY is not null)
  103. newPos = newPos.ReflectY((int)horAxisY);
  104. return new ChunkyImageOperation(imageToDraw, newPos, mirrorHorizontal ^ (verAxisX is not null), mirrorVertical ^ (horAxisY is not null));
  105. }
  106. public void Dispose() { }
  107. }