Browse Source

Shapes system is working

Frytek 5 years ago
parent
commit
15eadacbd6

+ 61 - 4
PixiEditorDotNetCore3/Models/Controllers/BitmapOperationsUtility.cs

@@ -5,6 +5,7 @@ using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
 using PixiEditor.Models.Tools;
 using System;
+using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Diagnostics;
 using System.Linq;
@@ -38,6 +39,19 @@ namespace PixiEditor.Models.Controllers
             }
         }
 
+        private Layer _previewLayer;
+
+        public Layer PreviewLayer
+        {
+            get { return _previewLayer; }
+            set 
+            {
+                _previewLayer = value;
+                RaisePropertyChanged("PreviewLayer");
+            }
+        }
+
+
         public Layer ActiveLayer => Layers.Count > 0 ? Layers[ActiveLayerIndex] : null;
 
         public Color PrimaryColor { get; set; }
@@ -47,21 +61,64 @@ namespace PixiEditor.Models.Controllers
         public event EventHandler<BitmapChangedEventArgs> BitmapChanged;
         public event EventHandler<LayersChangedEventArgs> LayersChanged;
 
+        private Coordinates _lastMousePos;
+        private BitmapPixelChanges _lastChangedPixels;
+
         public BitmapOperationsUtility()
         {
             MouseController = new MouseMovementController();
             MouseController.MousePositionChanged += Controller_MousePositionChanged;
+            MouseController.StoppedRecordingChanges += MouseController_StoppedRecordingChanges;
+        }
+
+        private void MouseController_StoppedRecordingChanges(object sender, EventArgs e)
+        {
+            if(SelectedTool.RequiresPreviewLayer)
+            {
+                Layers[ActiveLayerIndex].ApplyPixels(_lastChangedPixels);
+                _previewLayer.Clear();
+            }
         }
 
         private void Controller_MousePositionChanged(object sender, MouseMovementEventArgs e)
         {
             if(SelectedTool != null && Mouse.LeftButton == MouseButtonState.Pressed)
             {
-                var pixels = MouseController.LastMouseMoveCoordinates;
-                pixels.Reverse();
-                var changedPixels = SelectedTool.Use(Layers[ActiveLayerIndex], pixels.ToArray(), PrimaryColor, ToolSize);
-                ActiveLayer.ApplyPixels(changedPixels);
+                var mouseMove = MouseController.LastMouseMoveCoordinates.ToList();
+                mouseMove.Reverse();
+                BitmapPixelChanges changedPixels = new BitmapPixelChanges();
+                if (!SelectedTool.RequiresPreviewLayer)
+                {
+                    changedPixels = SelectedTool.Use(Layers[ActiveLayerIndex], mouseMove.ToArray(), PrimaryColor, ToolSize);
+                    ActiveLayer.ApplyPixels(changedPixels);
+                }
+                else
+                {
+                    UseToolOnPreviewLayer(mouseMove);
+                }
                 BitmapChanged?.Invoke(this, new BitmapChangedEventArgs(changedPixels, ActiveLayerIndex));
+                _lastMousePos = e.NewPosition;
+            }
+        }
+
+        private void UseToolOnPreviewLayer(List<Coordinates> mouseMove)
+        {
+            BitmapPixelChanges changedPixels;
+            if (mouseMove[0] != _lastMousePos)
+            {
+                GeneratePreviewLayer();
+                PreviewLayer.Clear();
+                changedPixels = SelectedTool.Use(Layers[ActiveLayerIndex], mouseMove.ToArray(), PrimaryColor, ToolSize);
+                PreviewLayer.ApplyPixels(changedPixels);
+                _lastChangedPixels = changedPixels;
+            }
+        }
+
+        private void GeneratePreviewLayer()
+        {
+            if (PreviewLayer == null)
+            {
+                PreviewLayer = new Layer("_previewLayer", Layers[0].Width, Layers[0].Height);
             }
         }
 

+ 3 - 1
PixiEditorDotNetCore3/Models/Controllers/MouseMovementController.cs

@@ -10,6 +10,7 @@ namespace PixiEditor.Models.Controllers
     {
         public List<Coordinates> LastMouseMoveCoordinates { get; } = new List<Coordinates>();
         public event EventHandler<MouseMovementEventArgs> MousePositionChanged;
+        public event EventHandler StoppedRecordingChanges;
         public bool IsRecordingChanges { get; private set; } = false;
 
         public void StartRecordingMouseMovementChanges()
@@ -20,7 +21,7 @@ namespace PixiEditor.Models.Controllers
                 IsRecordingChanges = true;
             }
         }
-        public void RecordMouseMovementChanges(Coordinates mouseCoordinates)
+        public void RecordMouseMovementChange(Coordinates mouseCoordinates)
         {
             if (IsRecordingChanges == true)
             {
@@ -37,6 +38,7 @@ namespace PixiEditor.Models.Controllers
             if (IsRecordingChanges)
             {
                 IsRecordingChanges = false;
+                StoppedRecordingChanges?.Invoke(this, EventArgs.Empty);
             }
         }
     }

+ 7 - 0
PixiEditorDotNetCore3/Models/Layers/Layer.cs

@@ -59,6 +59,13 @@ namespace PixiEditor.Models.Layers
             LayerBitmap.Unlock();
         }
 
+        public void Clear()
+        {
+            LayerBitmap.Lock();
+            LayerBitmap.Clear();
+            LayerBitmap.Unlock();
+        }
+
         public byte[] ConvertBitmapToBytes()
         {            
             LayerBitmap.Lock();

+ 1 - 1
PixiEditorDotNetCore3/Models/Position/DoubleCords.cs

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
 
 namespace PixiEditor.Models.Position
 {
-    public class DoubleCords
+    public struct DoubleCords
     {
         public Coordinates Coords1 { get; set; }
         public Coordinates Coords2 { get; set; }

+ 91 - 6
PixiEditorDotNetCore3/Models/Tools/ShapeTool.cs

@@ -11,16 +11,101 @@ namespace PixiEditor.Models.Tools
     {
         public override abstract ToolType ToolType { get; }
 
-        public ShapeTool()
-        {
-            ExecutesItself = true;
+        public abstract override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize);
+
+        public ShapeTool()
+        {
+            RequiresPreviewLayer = true;
         }
 
-        public abstract override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize);
+        protected Coordinates[] BresenhamLine(int x1, int y1, int x2, int y2)
+        {
+            List<Coordinates> coordinates = new List<Coordinates>();
+            if(x1 == x2 && y1 == y2)
+            {
+                return new Coordinates[] { new Coordinates(x1, y1) };
+            }
+
+            int d, dx, dy, ai, bi, xi, yi;
+            int x = x1, y = y1;
+
+            if (x1 < x2)
+            {
+                xi = 1;
+                dx = x2 - x1;
+            }
+            else
+            {
+                xi = -1;
+                dx = x1 - x2;
+            }
+
+            if (y1 < y2)
+            {
+                yi = 1;
+                dy = y2 - y1;
+            }
+            else
+            {
+                yi = -1;
+                dy = y1 - y2;
+            }
+            coordinates.Add(new Coordinates(x, y));
+
+            if (dx > dy)
+            {
+                ai = (dy - dx) * 2;
+                bi = dy * 2;
+                d = bi - dx;
+                
+                while (x != x2)
+                {
+                    
+                    if (d >= 0)
+                    {
+                        x += xi;
+                        y += yi;
+                        d += ai;
+                    }
+                    else
+                    {
+                        d += bi;
+                        x += xi;
+                    }
+                    coordinates.Add(new Coordinates(x, y));
+                }
+            }
+            else
+            {
+                ai = (dx - dy) * 2;
+                bi = dx * 2;
+                d = bi - dy;
+                
+                while (y != y2)
+                {
+                    
+                    if (d >= 0)
+                    {
+                        x += xi;
+                        y += yi;
+                        d += ai;
+                    }
+                    else
+                    {
+                        d += bi;
+                        y += yi;
+                    }
+                    coordinates.Add(new Coordinates(x, y));
+                }
+            }
+
+            return coordinates.ToArray();
+
+        }
 
-        protected DoubleCords CalculateCoordinatesForShapeRotation(Coordinates startingCords)
+        protected DoubleCords CalculateCoordinatesForShapeRotation(Coordinates startingCords, Coordinates secondCoordinates)
         {
-            Coordinates currentCoordinates = MousePositionConverter.CurrentCoordinates;
+            Coordinates currentCoordinates = secondCoordinates;
 
             if (startingCords.X > currentCoordinates.X && startingCords.Y > currentCoordinates.Y)
             {

+ 1 - 1
PixiEditorDotNetCore3/Models/Tools/Tool.cs

@@ -11,6 +11,6 @@ namespace PixiEditor.Models.Tools
     {
         public abstract BitmapPixelChanges Use(Layer layer, Coordinates[] pixels, Color color, int toolSize);
         public abstract ToolType ToolType { get; }
-        public bool ExecutesItself = false;
+        public bool RequiresPreviewLayer { get; set; }
     }
 }

+ 3 - 5
PixiEditorDotNetCore3/Models/Tools/Tools/CircleTool.cs

@@ -11,15 +11,13 @@ namespace PixiEditor.Models.Tools.Tools
 
         public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize)
         {
-            CreateCircle(layer, coordinates[0], color, toolSize);
+            CreateCircle(coordinates, color, toolSize);
             return new BitmapPixelChanges();
         }
 
-        public void CreateCircle(Layer layer, Coordinates coordinates, Color color, int size)
+        public void CreateCircle(Coordinates[] coordinates, Color color, int size)
         {
-            DoubleCords calculatedCords = CalculateCoordinatesForShapeRotation(coordinates);
-            layer.LayerBitmap.DrawEllipse(calculatedCords.Coords1.X, calculatedCords.Coords1.Y, calculatedCords.Coords2.X,
-                calculatedCords.Coords2.Y, color);
+            
         }
 
         

+ 0 - 5
PixiEditorDotNetCore3/Models/Tools/Tools/FloodFill.cs

@@ -11,11 +11,6 @@ namespace PixiEditor.Models.Tools.Tools
     {
         public override ToolType ToolType => ToolType.Bucket;
 
-        public FloodFill()
-        {
-            ExecutesItself = true;
-        }
-
         public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize)
         {
             return ForestFire(layer, coordinates[0], color);

+ 5 - 5
PixiEditorDotNetCore3/Models/Tools/Tools/LineTool.cs

@@ -11,14 +11,14 @@ namespace PixiEditor.Models.Tools.Tools
 
         public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize)
         {
-            CreateLine(layer, coordinates[0], color, toolSize);
-            return new BitmapPixelChanges();
+            return BitmapPixelChanges.FromSingleColoredArray(CreateLine(coordinates), color);
         }
 
-        public void CreateLine(Layer layer, Coordinates coordinates, Color color, int size)
+        public Coordinates[] CreateLine(Coordinates[] coordinates)
         {
-            layer.LayerBitmap.DrawLineBresenham(coordinates.X, coordinates.Y, MousePositionConverter.CurrentCoordinates.X,
-                MousePositionConverter.CurrentCoordinates.Y, color);
+            Coordinates startingCoordinates = coordinates[^1];
+            Coordinates latestCoordinates = coordinates[0];
+            return BresenhamLine(startingCoordinates.X, startingCoordinates.Y, latestCoordinates.X, latestCoordinates.Y);
         }
     }
 }

+ 24 - 6
PixiEditorDotNetCore3/Models/Tools/Tools/RectangleTool.cs

@@ -1,24 +1,42 @@
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using System.Collections.Generic;
+using System.Linq;
 using System.Windows.Media;
-using System.Windows.Media.Imaging;
 
 namespace PixiEditor.Models.Tools.Tools
 {
     public class RectangleTool : ShapeTool
     {
         public override ToolType ToolType => ToolType.Rectangle;
+        public bool Filled { get; set; } = false;
 
         public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize)
         {
-            CreateRectangle(layer,coordinates[0], color, toolSize);
-            return new BitmapPixelChanges();
+            return BitmapPixelChanges.FromSingleColoredArray(CreateRectangle(coordinates, toolSize), color);
         }
 
-        public void CreateRectangle(Layer layer, Coordinates startingCoords, Color color, int toolSize)
+        public Coordinates[] CreateRectangle(Coordinates[] coordinates, int toolSize)
         {
-            DoubleCords coordinates = CalculateCoordinatesForShapeRotation(startingCoords);
-            layer.LayerBitmap.DrawRectangle(coordinates.Coords1.X, coordinates.Coords1.Y, coordinates.Coords2.X, coordinates.Coords2.Y, color);
+            DoubleCords fixedCoordinates = CalculateCoordinatesForShapeRotation(coordinates[^1], coordinates[0]);
+            return CalculateRectanglePoints(fixedCoordinates, Filled);
+        }
+
+        private Coordinates[] CalculateRectanglePoints(DoubleCords coordinates, bool filled)
+        {
+            List<Coordinates> finalCoordinates = new List<Coordinates>();
+            for (int i = coordinates.Coords1.X; i < coordinates.Coords2.X; i++)
+            {
+                finalCoordinates.Add(new Coordinates(i, coordinates.Coords1.Y));
+                finalCoordinates.Add(new Coordinates(i, coordinates.Coords2.Y));
+            }
+            for (int i = coordinates.Coords1.Y; i < coordinates.Coords2.Y + 1; i++)
+            {
+                finalCoordinates.Add(new Coordinates(coordinates.Coords1.X, i));
+                finalCoordinates.Add(new Coordinates(coordinates.Coords2.X, i));
+            }
+            finalCoordinates = finalCoordinates.Distinct().ToList();
+            return finalCoordinates.ToArray();
         }
     }
 }

+ 0 - 126
PixiEditorDotNetCore3/Models/Tools/ToolsManager.cs

@@ -1,126 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Media;
-using System.Windows.Input;
-using System.Windows.Media.Imaging;
-using PixiEditor.ViewModels;
-using System.Timers;
-using System.Windows.Threading;
-using System.Threading;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-
-namespace PixiEditor.Models.Tools
-{
-    public class ToolsManager
-    {
-        public List<Tool> Tools { get; set; } = new List<Tool>();
-        public Tool SelectedTool { get; private set; }
-        private bool _toolRecievedData = false;
-
-        private System.Timers.Timer _loopTimer;
-        private Layer _layer;
-        private WriteableBitmap _clonedBitmap;
-        private Coordinates _startCoordinates;
-        private Color _color;
-        private int _toolSzie;
-
-        public ToolsManager(List<Tool> tools)
-        {
-            Tools = tools;
-            _loopTimer = new System.Timers.Timer
-            {
-                Interval = 15,
-                Enabled = false,
-                AutoReset = true
-            };
-            _loopTimer.Elapsed += LoopTimer_Elapsed;
-        }
-
-        private void LoopTimer_Elapsed(object sender, ElapsedEventArgs e)
-        {
-            Application.Current.Dispatcher.Invoke(() =>
-            {
-                _layer.LayerBitmap.Lock();
-
-                if (_clonedBitmap != null)
-                {
-                    RestoreLastBitmap();
-                }
-
-                BitmapPixelChanges changes = SelectedTool.Use(_layer, new[] { _startCoordinates }, _color, _toolSzie);
-
-                if (!SelectedTool.ExecutesItself)
-                {
-                    _layer.ApplyPixels(changes);
-                }
-                _layer.LayerBitmap.Unlock();
-
-            });
-        }
-
-        private void RestoreLastBitmap()
-        {
-            _layer.LayerBitmap.Clear();
-            _layer.LayerBitmap.Blit(new Rect(new Size(_layer.Width, _layer.Height)), _clonedBitmap, new Rect(new Size(_layer.Width, _layer.Height)), WriteableBitmapExtensions.BlendMode.Additive);
-        }
-
-        public void SetTool(ToolType tool)
-        {
-            SelectedTool = Tools.Find(x => x.ToolType == tool);
-        }
-
-        public void StopExectuingTool()
-        {
-            _loopTimer.Enabled = false;
-            _toolRecievedData = false;
-            _clonedBitmap = null;
-        }
-
-        private void StartTimer()
-        {
-            _toolRecievedData = true;
-            _loopTimer.Enabled = true;
-        }
-
-        private void CloneBitmapIfToolIsShape()
-        {
-            if (SelectedTool.GetType().BaseType == typeof(ShapeTool))
-            {
-                _clonedBitmap = _layer.LayerBitmap.Clone();
-            }
-        }
-
-        /// <summary>
-        /// Executes tool action
-        /// </summary>
-        /// <param name="layer">Layer to operate on.</param>
-        /// <param name="startingCoords">Click coordinates.</param>
-        /// <param name="color">Color that tool will use.</param>
-        /// <param name="toolSize">Size/thickness of tool</param>
-        /// <param name="tool">Tool to execute</param>
-        /// <returns></returns>
-        public void ExecuteTool(Layer layer, Coordinates startingCoords, Color color, int toolSize)
-        {
-            if (toolSize < 1)
-                return;
-
-            if (_toolRecievedData == false || (_toolRecievedData == true && SelectedTool.GetType().BaseType != typeof(ShapeTool)))
-            {
-                _startCoordinates = startingCoords;
-                _layer = layer;
-                _color = color;
-                _toolSzie = toolSize;
-            }
-
-            if (_loopTimer.Enabled == false)
-            {
-                StartTimer();
-                CloneBitmapIfToolIsShape();
-            }
-        }
-
-    }
-}

+ 8 - 9
PixiEditorDotNetCore3/ViewModels/ViewModelMain.cs

@@ -110,7 +110,8 @@ namespace PixiEditor.ViewModels
             }
         }
 
-        private ToolsManager primaryToolSet;
+        public List<Tool> ToolSet { get; set; }
+
 
         public BitmapOperationsUtility BitmapUtility { get; set; }
 
@@ -130,8 +131,8 @@ namespace PixiEditor.ViewModels
             OpenFileCommand = new RelayCommand(OpenFile);
             SetActiveLayerCommand = new RelayCommand(SetActiveLayer);
             NewLayerCommand = new RelayCommand(NewLayer, CanCreateNewLayer);
-            primaryToolSet = new ToolsManager(new List<Tool> { new PixiTools.PenTool(), new PixiTools.FloodFill(), new PixiTools.LineTool(),
-            new PixiTools.CircleTool(), new PixiTools.RectangleTool(), new PixiTools.EarserTool(), new PixiTools.BrightnessTool()});
+            ToolSet = new List<Tool> { new PixiTools.PenTool(), new PixiTools.FloodFill(), new PixiTools.LineTool(),
+            new PixiTools.CircleTool(), new PixiTools.RectangleTool(), new PixiTools.EarserTool(), new PixiTools.BrightnessTool() };       
             UndoManager.SetMainRoot(this);
             SetActiveTool(ToolType.Pen);
             BitmapUtility.PrimaryColor = PrimaryColor;
@@ -192,8 +193,7 @@ namespace PixiEditor.ViewModels
 
         private void SetActiveTool(ToolType tool)
         {
-            primaryToolSet.SetTool(tool);
-            BitmapUtility.SelectedTool = primaryToolSet.SelectedTool;
+            BitmapUtility.SelectedTool = ToolSet.Find(x=> x.ToolType == tool);
         }
         /// <summary>
         /// When mouse is up stops recording changes.
@@ -203,7 +203,6 @@ namespace PixiEditor.ViewModels
         {
             UndoManager.StopRecording();
             BitmapUtility.MouseController.StopRecordingMouseMovementChanges();
-            primaryToolSet.StopExectuingTool();
         }
 
         private void MouseDown(object parameter)
@@ -211,7 +210,7 @@ namespace PixiEditor.ViewModels
             if (!BitmapUtility.MouseController.IsRecordingChanges)
             {
                 BitmapUtility.MouseController.StartRecordingMouseMovementChanges();
-                BitmapUtility.MouseController.RecordMouseMovementChanges(MousePositionConverter.CurrentCoordinates);
+                BitmapUtility.MouseController.RecordMouseMovementChange(MousePositionConverter.CurrentCoordinates);
             }
         }
 
@@ -224,9 +223,9 @@ namespace PixiEditor.ViewModels
             Coordinates cords = new Coordinates((int)MouseXOnCanvas, (int)MouseYOnCanvas);
             MousePositionConverter.CurrentCoordinates = cords;
 
-                if (BitmapUtility.MouseController.IsRecordingChanges)
+                if (BitmapUtility.MouseController.IsRecordingChanges && Mouse.LeftButton == MouseButtonState.Pressed)
                 {
-                    BitmapUtility.MouseController.RecordMouseMovementChanges(cords);
+                    BitmapUtility.MouseController.RecordMouseMovementChange(cords);
                 }
         }
 

+ 1 - 0
PixiEditorDotNetCore3/Views/MainWindow.xaml

@@ -127,6 +127,7 @@
                                 <behaviors:MouseBehaviour MouseX="{Binding MouseXOnCanvas, Mode=OneWayToSource}" MouseY="{Binding MouseYOnCanvas, Mode=OneWayToSource}"/>
                             </i:Interaction.Behaviors>
                             <Image Source="/Images/transparentbg.png" Height="{Binding BitmapUtility.ActiveLayer.Height}" Width="{Binding BitmapUtility.ActiveLayer.Width}" Opacity="0.2" Stretch="UniformToFill"/>
+                            <Image Source="{Binding BitmapUtility.PreviewLayer.LayerBitmap}" Panel.ZIndex="2" RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Uniform" Width="{Binding BitmapUtility.PreviewLayer.Width}" Height="{Binding BitmapUtility.PreviewLayer.Height}"/>
                             <ItemsControl ItemsSource="{Binding BitmapUtility.Layers}">
                                 <ItemsControl.ItemsPanel>
                                     <ItemsPanelTemplate>