Browse Source

Minor refactor

Equbuxu 3 years ago
parent
commit
ef00043cc2

+ 17 - 22
src/ChunkyImageLib/ChunkyImage.cs

@@ -22,7 +22,7 @@ namespace ChunkyImageLib
     ///     - latestChunks stores chunks with some (or none, or all) queued operations applied
     ///     - latestChunksData stores the data for some or all of the latest chunks (not necessarily synced with latestChunks).
     ///         The data includes how many operations from the queue have already been applied to the chunk, as well as chunk deleted state (the clear operation deletes chunks)
-    ///     - LatestSize contains new size if any resize operations were requested, otherwise commited size
+    ///     - LatestSize contains the new size if any resize operations were requested, otherwise the commited size
     /// You can check the current state via queuedOperations.Count == 0
     /// </summary>
     public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
@@ -131,6 +131,14 @@ namespace ChunkyImageLib
             }
         }
 
+        internal bool CommitedChunkExists(Vector2i chunkPos, ChunkResolution resolution)
+        {
+            lock (lockObject)
+            {
+                return GetCommittedChunk(chunkPos, resolution) is not null;
+            }
+        }
+
         /// <summary>
         /// Returns the latest version of the chunk, with uncommitted changes applied if they exist
         /// </summary>
@@ -401,7 +409,7 @@ namespace ChunkyImageLib
                 return;
 
             Chunk? targetChunk = null;
-            List<Chunk> activeClips = new();
+            List<ChunkyImage> activeClips = new();
             bool isFullyMaskedOut = false;
             bool somethingWasApplied = false;
             for (int i = 0; i < queuedOperations.Count; i++)
@@ -409,9 +417,8 @@ namespace ChunkyImageLib
                 var (operation, operChunks) = queuedOperations[i];
                 if (operation is RasterClipOperation clipOperation)
                 {
-                    var chunk = clipOperation.ClippingMask.GetCommittedChunk(chunkPos, resolution);
-                    if (chunk is not null)
-                        activeClips.Add(chunk);
+                    if (clipOperation.ClippingMask.CommitedChunkExists(chunkPos, resolution))
+                        activeClips.Add(clipOperation.ClippingMask);
                     else
                         isFullyMaskedOut = true;
                 }
@@ -425,7 +432,7 @@ namespace ChunkyImageLib
                 }
 
                 if (chunkData.QueueProgress <= i)
-                    chunkData.IsDeleted = ApplyOperationToChunk(operation, activeClips, isFullyMaskedOut, targetChunk!, chunkPos, chunkData);
+                    chunkData.IsDeleted = ApplyOperationToChunk(operation, activeClips, isFullyMaskedOut, targetChunk!, chunkPos, resolution, chunkData);
             }
 
             if (somethingWasApplied)
@@ -437,10 +444,11 @@ namespace ChunkyImageLib
 
         private bool ApplyOperationToChunk(
             IOperation operation,
-            List<Chunk> activeClips,
+            List<ChunkyImage> activeClips,
             bool isFullyMaskedOut,
             Chunk targetChunk,
             Vector2i chunkPos,
+            ChunkResolution resolution,
             LatestChunkData chunkData)
         {
             if (operation is ClearOperation)
@@ -464,7 +472,7 @@ namespace ChunkyImageLib
                 chunkOperation.DrawOnChunk(tempChunk, chunkPos);
                 foreach (var mask in activeClips)
                 {
-                    mask.DrawOnSurface(tempChunk.Surface.SkiaSurface, new(0, 0), ClippingPaint);
+                    mask.DrawCommittedChunkOn(chunkPos, resolution, tempChunk.Surface.SkiaSurface, new(0, 0), ClippingPaint);
                 }
                 tempChunk.DrawOnSurface(targetChunk.Surface.SkiaSurface, new(0, 0));
                 return false;
@@ -508,7 +516,7 @@ namespace ChunkyImageLib
             HashSet<Vector2i> toRemove = new();
             foreach (var (pos, chunk) in committedChunks[ChunkResolution.Full])
             {
-                if (IsChunkEmpty(chunk))
+                if (chunk.Surface.IsFullyTransparent())
                 {
                     toRemove.Add(pos);
                     chunk.Dispose();
@@ -523,19 +531,6 @@ namespace ChunkyImageLib
             }
         }
 
-        private unsafe bool IsChunkEmpty(Chunk chunk)
-        {
-            ulong* ptr = (ulong*)chunk.Surface.PixelBuffer;
-            for (int i = 0; i < ChunkSize * ChunkSize; i++)
-            {
-                // ptr[i] actually contains 4 16-bit floats. We only care about the first one which is alpha.
-                // An empty pixel can have alpha of 0 or -0 (not sure if -0 actually ever comes up). 0 in hex is 0x0, -0 in hex is 0x8000
-                if ((ptr[i] & 0x1111_0000_0000_0000) != 0 && (ptr[i] & 0x1111_0000_0000_0000) != 0x8000_0000_0000_0000)
-                    return false;
-            }
-            return true;
-        }
-
         private Chunk GetOrCreateCommittedChunk(Vector2i chunkPos, ChunkResolution resolution)
         {
             // commited chunk of the same resolution exists

+ 13 - 0
src/ChunkyImageLib/Surface.cs

@@ -49,6 +49,19 @@ namespace ChunkyImageLib
             return (SKColor)new SKColorF((float)ptr[0] / a, (float)ptr[1] / a, (float)ptr[2] / a, (float)ptr[3]);*/
         }
 
+        public unsafe bool IsFullyTransparent()
+        {
+            ulong* ptr = (ulong*)PixelBuffer;
+            for (int i = 0; i < Size.X * Size.Y; i++)
+            {
+                // ptr[i] actually contains 4 16-bit floats. We only care about the first one which is alpha.
+                // An empty pixel can have alpha of 0 or -0 (not sure if -0 actually ever comes up). 0 in hex is 0x0, -0 in hex is 0x8000
+                if ((ptr[i] & 0x1111_0000_0000_0000) != 0 && (ptr[i] & 0x1111_0000_0000_0000) != 0x8000_0000_0000_0000)
+                    return false;
+            }
+            return true;
+        }
+
         public void SaveToDesktop(string filename = "savedSurface.png")
         {
             using var final = SKSurface.Create(new SKImageInfo(Size.X, Size.Y, SKColorType.Rgba8888, SKAlphaType.Premul, SKColorSpace.CreateSrgb()));

+ 0 - 62
src/ChunkyImageLib/SurfacePool.cs

@@ -1,62 +0,0 @@
-using ChunkyImageLib.DataHolders;
-using System.Collections.Concurrent;
-
-namespace ChunkyImageLib
-{
-    internal class SurfacePool
-    {
-        //must be divisible by 8
-        public const int FullChunkSize = 256;
-
-        private static object lockObj = new();
-        private static SurfacePool? instance;
-        public static SurfacePool Instance
-        {
-            get
-            {
-                if (instance is null)
-                {
-                    lock (lockObj)
-                    {
-                        if (instance is null)
-                            instance = new SurfacePool();
-                    }
-                }
-                return instance;
-            }
-        }
-
-        private readonly ConcurrentBag<Surface> fullSurfaces = new();
-        private readonly ConcurrentBag<Surface> halfSurfaces = new();
-        private readonly ConcurrentBag<Surface> quarterSurfaces = new();
-        private readonly ConcurrentBag<Surface> eighthSurfaces = new();
-        internal Surface Get(ChunkResolution resolution)
-        {
-            if (GetBag(resolution).TryTake(out Surface? item))
-                return item;
-            return new Surface(new Vector2i(resolution.PixelSize(), resolution.PixelSize()));
-        }
-
-        private ConcurrentBag<Surface> GetBag(ChunkResolution resolution)
-        {
-            return resolution switch
-            {
-                ChunkResolution.Full => fullSurfaces,
-                ChunkResolution.Half => halfSurfaces,
-                ChunkResolution.Quarter => quarterSurfaces,
-                ChunkResolution.Eighth => eighthSurfaces,
-                _ => fullSurfaces
-            };
-        }
-
-        internal void Push(Surface surface, ChunkResolution resolution)
-        {
-            var surfaces = GetBag(resolution);
-            //a race condition can cause the count to go above 200, but likely not by much
-            if (surfaces.Count < 200)
-                surfaces.Add(surface);
-            else
-                surface.Dispose();
-        }
-    }
-}

+ 2 - 1
src/ChunkyImageLibBenchmark/Program.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib;
+using ChunkyImageLib.DataHolders;
 using SkiaSharp;
 using System.Diagnostics;
 
@@ -23,7 +24,7 @@ Console.ReadKey();
 
 (double first, double second) Benchmark()
 {
-    using ChunkyImage image = new(new(1024, 1024));
+    using ChunkyImage image = new(new(1024, 1024), ColorType.RgbaF16);
     image.DrawRectangle(new(new(0, 0), new(1024, 1024), 10, SKColors.Black, SKColors.Bisque));
 
     Stopwatch sw = Stopwatch.StartNew();