BitmapOperationsUtility.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. using PixiEditor.Helpers;
  2. using PixiEditor.Models.Controllers;
  3. using PixiEditor.Models.Enums;
  4. using PixiEditor.Models.Layers;
  5. using PixiEditor.Models.Position;
  6. using PixiEditor.Models.Tools;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Collections.ObjectModel;
  10. using System.Diagnostics;
  11. using System.Linq;
  12. using System.Windows.Input;
  13. using System.Windows.Media;
  14. using System.Windows.Media.Imaging;
  15. namespace PixiEditor.Models.Controllers
  16. {
  17. public class BitmapOperationsUtility : NotifyableObject
  18. {
  19. public MouseMovementController MouseController { get; set; }
  20. public Tool SelectedTool { get; set; }
  21. private ObservableCollection<Layer> _layers = new ObservableCollection<Layer>();
  22. public ObservableCollection<Layer> Layers
  23. {
  24. get => _layers;
  25. set { if (_layers != value) { _layers = value; } }
  26. }
  27. private int _activeLayerIndex;
  28. public int ActiveLayerIndex
  29. {
  30. get => _activeLayerIndex;
  31. set
  32. {
  33. _activeLayerIndex = value;
  34. RaisePropertyChanged("ActiveLayerIndex");
  35. RaisePropertyChanged("ActiveLayer");
  36. }
  37. }
  38. private Layer _previewLayer;
  39. public Layer PreviewLayer
  40. {
  41. get { return _previewLayer; }
  42. set
  43. {
  44. _previewLayer = value;
  45. RaisePropertyChanged("PreviewLayer");
  46. }
  47. }
  48. public Layer ActiveLayer => Layers.Count > 0 ? Layers[ActiveLayerIndex] : null;
  49. public Color PrimaryColor { get; set; }
  50. public int ToolSize { get; set; }
  51. public event EventHandler<BitmapChangedEventArgs> BitmapChanged;
  52. public event EventHandler<LayersChangedEventArgs> LayersChanged;
  53. private Coordinates _lastMousePos;
  54. private BitmapPixelChanges _lastChangedPixels;
  55. public BitmapOperationsUtility()
  56. {
  57. MouseController = new MouseMovementController();
  58. MouseController.MousePositionChanged += Controller_MousePositionChanged;
  59. MouseController.StoppedRecordingChanges += MouseController_StoppedRecordingChanges;
  60. }
  61. private void MouseController_StoppedRecordingChanges(object sender, EventArgs e)
  62. {
  63. if(SelectedTool.RequiresPreviewLayer)
  64. {
  65. BitmapPixelChanges oldValues = GetOldPixelsValues(_lastChangedPixels.ChangedPixels.Keys.ToArray());
  66. Layers[ActiveLayerIndex].ApplyPixels(_lastChangedPixels);
  67. BitmapChanged?.Invoke(this, new BitmapChangedEventArgs(_lastChangedPixels, oldValues, ActiveLayerIndex));
  68. _previewLayer.Clear();
  69. }
  70. }
  71. private void Controller_MousePositionChanged(object sender, MouseMovementEventArgs e)
  72. {
  73. if(SelectedTool != null && SelectedTool.ToolType != ToolType.None && Mouse.LeftButton == MouseButtonState.Pressed)
  74. {
  75. var mouseMove = MouseController.LastMouseMoveCoordinates.ToList();
  76. mouseMove.Reverse();
  77. if (!SelectedTool.RequiresPreviewLayer)
  78. {
  79. BitmapPixelChanges changedPixels = SelectedTool.Use(Layers[ActiveLayerIndex], mouseMove.ToArray(), PrimaryColor, ToolSize);
  80. BitmapPixelChanges oldPixelsValues = GetOldPixelsValues(changedPixels.ChangedPixels.Keys.ToArray());
  81. ActiveLayer.ApplyPixels(changedPixels);
  82. BitmapChanged?.Invoke(this, new BitmapChangedEventArgs(changedPixels, oldPixelsValues, ActiveLayerIndex));
  83. }
  84. else
  85. {
  86. UseToolOnPreviewLayer(mouseMove);
  87. }
  88. _lastMousePos = e.NewPosition;
  89. }
  90. }
  91. private BitmapPixelChanges GetOldPixelsValues(Coordinates[] coordinates)
  92. {
  93. Dictionary<Coordinates, Color> values = new Dictionary<Coordinates, Color>();
  94. Layers[ActiveLayerIndex].LayerBitmap.Lock();
  95. for (int i = 0; i < coordinates.Length; i++)
  96. {
  97. values.Add(coordinates[i], Layers[ActiveLayerIndex].LayerBitmap.GetPixel(coordinates[i].X, coordinates[i].Y));
  98. }
  99. Layers[ActiveLayerIndex].LayerBitmap.Unlock();
  100. return new BitmapPixelChanges(values);
  101. }
  102. private void UseToolOnPreviewLayer(List<Coordinates> mouseMove)
  103. {
  104. BitmapPixelChanges changedPixels;
  105. if (mouseMove[0] != _lastMousePos)
  106. {
  107. GeneratePreviewLayer();
  108. PreviewLayer.Clear();
  109. changedPixels = SelectedTool.Use(Layers[ActiveLayerIndex], mouseMove.ToArray(), PrimaryColor, ToolSize);
  110. PreviewLayer.ApplyPixels(changedPixels);
  111. _lastChangedPixels = changedPixels;
  112. }
  113. }
  114. private void GeneratePreviewLayer()
  115. {
  116. if (PreviewLayer == null)
  117. {
  118. PreviewLayer = new Layer("_previewLayer", Layers[0].Width, Layers[0].Height);
  119. }
  120. }
  121. public void RemoveLayer(int layerIndex)
  122. {
  123. if (Layers.Count <= 1) return;
  124. bool wasActive = Layers[layerIndex].IsActive;
  125. Layers.RemoveAt(layerIndex);
  126. if (wasActive)
  127. {
  128. SetActiveLayer(0);
  129. }
  130. else if(ActiveLayerIndex > Layers.Count - 1)
  131. {
  132. SetActiveLayer(Layers.Count - 1);
  133. }
  134. }
  135. public void AddNewLayer(string name, int width, int height, bool setAsActive = true)
  136. {
  137. Layers.Add(new Layer(name, width, height));
  138. if (setAsActive)
  139. {
  140. SetActiveLayer(Layers.Count - 1);
  141. }
  142. LayersChanged?.Invoke(this, new LayersChangedEventArgs(0, LayerAction.Add));
  143. }
  144. public void SetActiveLayer(int index)
  145. {
  146. if (ActiveLayerIndex <= Layers.Count - 1)
  147. {
  148. Layers[ActiveLayerIndex].IsActive = false;
  149. }
  150. ActiveLayerIndex = index;
  151. Layers[ActiveLayerIndex].IsActive = true;
  152. LayersChanged?.Invoke(this, new LayersChangedEventArgs(index, LayerAction.SetActive));
  153. }
  154. public WriteableBitmap GetCombinedLayersBitmap()
  155. {
  156. WriteableBitmap finalBitmap = Layers[0].LayerBitmap.Clone();
  157. finalBitmap.Lock();
  158. for (int i = 1; i < Layers.Count; i++)
  159. {
  160. for (int y = 0; y < finalBitmap.Height; y++)
  161. {
  162. for (int x = 0; x < finalBitmap.Width; x++)
  163. {
  164. Color color = Layers[i].LayerBitmap.GetPixel(x, y);
  165. if (color.A != 0 || color.R != 0 || color.B != 0 || color.G != 0)
  166. {
  167. finalBitmap.SetPixel(x, y, color);
  168. }
  169. }
  170. }
  171. }
  172. finalBitmap.Unlock();
  173. return finalBitmap;
  174. }
  175. }
  176. }
  177. public class BitmapChangedEventArgs : EventArgs
  178. {
  179. public BitmapPixelChanges PixelsChanged { get; set; }
  180. public BitmapPixelChanges OldPixelsValues { get; set; }
  181. public int ChangedLayerIndex { get; set; }
  182. public BitmapChangedEventArgs(BitmapPixelChanges pixelsChanged, BitmapPixelChanges oldPixelsValues, int changedLayerIndex)
  183. {
  184. PixelsChanged = pixelsChanged;
  185. OldPixelsValues = oldPixelsValues;
  186. ChangedLayerIndex = changedLayerIndex;
  187. }
  188. }
  189. public class LayersChangedEventArgs : EventArgs
  190. {
  191. public int LayerAffected { get; set; }
  192. public LayerAction LayerChangeType { get; set; }
  193. public LayersChangedEventArgs(int layerAffected, LayerAction layerChangeType)
  194. {
  195. LayerAffected = layerAffected;
  196. LayerChangeType = layerChangeType;
  197. }
  198. }