Procházet zdrojové kódy

Initial implementation of layer previews

Equbuxu před 4 roky
rodič
revize
06a0b7f1ff

+ 39 - 0
PixiEditor/Models/Controllers/SurfaceRenderer.cs

@@ -0,0 +1,39 @@
+using PixiEditor.Models.DataHolders;
+using SkiaSharp;
+using System;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace PixiEditor.Models.Controllers
+{
+    class SurfaceRenderer : IDisposable
+    {
+        public SKSurface BackingSurface { get; private set; }
+        public WriteableBitmap FinalBitmap { get; private set; }
+        private SKPaint BlendingPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.SrcOver };
+        public SurfaceRenderer(int width, int height)
+        {
+            FinalBitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Pbgra32, null);
+            var imageInfo = new SKImageInfo(width, height, SKColorType.Bgra8888, SKAlphaType.Premul, SKColorSpace.CreateSrgb());
+            BackingSurface = SKSurface.Create(imageInfo, FinalBitmap.BackBuffer, FinalBitmap.BackBufferStride);
+        }
+
+        public void Dispose()
+        {
+            BackingSurface.Dispose();
+            BlendingPaint.Dispose();
+        }
+
+        public void Draw(Surface otherSurface, byte opacity)
+        {
+            BackingSurface.Canvas.Clear();
+            FinalBitmap.Lock();
+            BlendingPaint.Color = new SKColor(255, 255, 255, opacity);
+            //otherSurface.SkiaSurface.Draw(BackingSurface.Canvas, 0, 0, BlendingPaint);
+            BackingSurface.Canvas.DrawImage(otherSurface.SkiaSurface.Snapshot(), new SKRect(0, 0, FinalBitmap.PixelWidth, FinalBitmap.PixelHeight));
+            FinalBitmap.AddDirtyRect(new Int32Rect(0, 0, FinalBitmap.PixelWidth, FinalBitmap.PixelHeight));
+            FinalBitmap.Unlock();
+        }
+    }
+}

+ 4 - 2
PixiEditor/Views/UserControls/Layers/LayerItem.xaml

@@ -4,6 +4,7 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:local="clr-namespace:PixiEditor.Views"
+             xmlns:controls="clr-namespace:PixiEditor.Views.UserControls"
              xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours" xmlns:layers="clr-namespace:PixiEditor.Models.Layers" xmlns:helpers="clr-namespace:PixiEditor.Helpers.UI"
              mc:Ignorable="d" Focusable="True"
              d:DesignHeight="60" d:DesignWidth="250" Name="uc"
@@ -39,8 +40,9 @@
                     <Rectangle Width="{Binding Path=(helpers:TreeViewItemHelper.Indent).Value, Mode=OneWay, RelativeSource={RelativeSource AncestorType=ItemsPresenter}}" Fill="Transparent" StrokeThickness="0"/>
                     <Border Width="30" Height="30" BorderThickness="1" BorderBrush="Black" Background="{StaticResource MainColor}"
                            Margin="5, 0, 10, 0">
-                        <Image Source="{Binding PreviewImage,ElementName=uc}" Stretch="Uniform" Width="20" Height="20" 
-                       RenderOptions.BitmapScalingMode="NearestNeighbor"/>
+                        <controls:PlainLayerView TargetLayer="{Binding LayerForPreview, ElementName=uc}"/>
+                        <!--<Image Source="{Binding PreviewImage,ElementName=uc}" Stretch="Uniform" Width="20" Height="20"
+                       RenderOptions.BitmapScalingMode="NearestNeighbor"/>-->
                     </Border>
 
                     <local:EditableTextBlock

+ 16 - 17
PixiEditor/Views/UserControls/Layers/LayerItem.xaml.cs

@@ -1,12 +1,11 @@
 using PixiEditor.Helpers;
 using PixiEditor.Models.DataHolders;
-using PixiEditor.Views.UserControls;
+using PixiEditor.Models.Layers;
 using System;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Media;
-using System.Windows.Media.Imaging;
 
 namespace PixiEditor.Views.UserControls.Layers
 {
@@ -23,7 +22,7 @@ namespace PixiEditor.Views.UserControls.Layers
         }
 
         public static readonly DependencyProperty IsRenamingProperty = DependencyProperty.Register(
-            "IsRenaming", typeof(bool), typeof(LayerItem), new PropertyMetadata(default(bool)));
+            nameof(IsRenaming), typeof(bool), typeof(LayerItem), new PropertyMetadata(default(bool)));
 
         public bool IsRenaming
         {
@@ -32,7 +31,7 @@ namespace PixiEditor.Views.UserControls.Layers
         }
 
         public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register(
-            "IsActive", typeof(bool), typeof(LayerItem), new PropertyMetadata(default(bool)));
+            nameof(IsActive), typeof(bool), typeof(LayerItem), new PropertyMetadata(default(bool)));
 
         public bool IsActive
         {
@@ -41,7 +40,7 @@ namespace PixiEditor.Views.UserControls.Layers
         }
 
         public static readonly DependencyProperty SetActiveLayerCommandProperty = DependencyProperty.Register(
-            "SetActiveLayerCommand", typeof(RelayCommand), typeof(LayerItem), new PropertyMetadata(default(RelayCommand)));
+            nameof(SetActiveLayerCommand), typeof(RelayCommand), typeof(LayerItem), new PropertyMetadata(default(RelayCommand)));
 
         public RelayCommand SetActiveLayerCommand
         {
@@ -50,7 +49,7 @@ namespace PixiEditor.Views.UserControls.Layers
         }
 
         public static readonly DependencyProperty LayerIndexProperty = DependencyProperty.Register(
-            "LayerIndex", typeof(int), typeof(LayerItem), new PropertyMetadata(default(int)));
+            nameof(LayerIndex), typeof(int), typeof(LayerItem), new PropertyMetadata(default(int)));
 
         public int LayerIndex
         {
@@ -59,7 +58,7 @@ namespace PixiEditor.Views.UserControls.Layers
         }
 
         public static readonly DependencyProperty LayerNameProperty = DependencyProperty.Register(
-            "LayerName", typeof(string), typeof(LayerItem), new PropertyMetadata(default(string)));
+            nameof(LayerName), typeof(string), typeof(LayerItem), new PropertyMetadata(default(string)));
 
         public string LayerName
         {
@@ -74,19 +73,19 @@ namespace PixiEditor.Views.UserControls.Layers
         }
 
         public static readonly DependencyProperty LayerGuidProperty =
-            DependencyProperty.Register("LayerGuid", typeof(Guid), typeof(LayerItem), new PropertyMetadata(default(Guid)));
+            DependencyProperty.Register(nameof(LayerGuid), typeof(Guid), typeof(LayerItem), new PropertyMetadata(default(Guid)));
 
         public static readonly DependencyProperty ControlButtonsVisibleProperty = DependencyProperty.Register(
-            "ControlButtonsVisible", typeof(Visibility), typeof(LayerItem), new PropertyMetadata(System.Windows.Visibility.Hidden));
+            nameof(ControlButtonsVisible), typeof(Visibility), typeof(LayerItem), new PropertyMetadata(System.Windows.Visibility.Hidden));
 
-        public WriteableBitmap PreviewImage
+        public Layer LayerForPreview
         {
-            get { return (WriteableBitmap)GetValue(PreviewImageProperty); }
-            set { SetValue(PreviewImageProperty, value); }
+            get { return (Layer)GetValue(LayerForPreviewProperty); }
+            set { SetValue(LayerForPreviewProperty, value); }
         }
 
-        public static readonly DependencyProperty PreviewImageProperty =
-            DependencyProperty.Register("PreviewImage", typeof(WriteableBitmap), typeof(LayerItem), new PropertyMetadata(null));
+        public static readonly DependencyProperty LayerForPreviewProperty =
+            DependencyProperty.Register(nameof(LayerForPreview), typeof(Layer), typeof(LayerItem), new PropertyMetadata(null));
 
         public string LayerColor
         {
@@ -95,7 +94,7 @@ namespace PixiEditor.Views.UserControls.Layers
         }
 
         public static readonly DependencyProperty LayerColorProperty =
-            DependencyProperty.Register("LayerColor", typeof(string), typeof(LayerItem), new PropertyMetadata("#00000000"));
+            DependencyProperty.Register(nameof(LayerColor), typeof(string), typeof(LayerItem), new PropertyMetadata("#00000000"));
 
         public Visibility ControlButtonsVisible
         {
@@ -110,10 +109,10 @@ namespace PixiEditor.Views.UserControls.Layers
         }
 
         public static readonly DependencyProperty MoveToBackCommandProperty =
-            DependencyProperty.Register("MoveToBackCommand", typeof(RelayCommand), typeof(LayerItem), new PropertyMetadata(default(RelayCommand)));
+            DependencyProperty.Register(nameof(MoveToBackCommand), typeof(RelayCommand), typeof(LayerItem), new PropertyMetadata(default(RelayCommand)));
 
         public static readonly DependencyProperty MoveToFrontCommandProperty = DependencyProperty.Register(
-            "MoveToFrontCommand", typeof(RelayCommand), typeof(LayerItem), new PropertyMetadata(default(RelayCommand)));
+            nameof(MoveToFrontCommand), typeof(RelayCommand), typeof(LayerItem), new PropertyMetadata(default(RelayCommand)));
 
         public RelayCommand MoveToFrontCommand
         {

+ 1 - 1
PixiEditor/Views/UserControls/Layers/LayerStructureItemContainer.xaml

@@ -11,7 +11,7 @@
                                        LayerName="{Binding Name, Mode=TwoWay}" 
                                        IsActive="{Binding IsActive, Mode=TwoWay}"
                                        IsRenaming="{Binding IsRenaming, Mode=TwoWay}"
-                                       PreviewImage="{Binding LayerBitmap}"
+                                       LayerForPreview="{Binding}"
                                        LayerGuid="{Binding LayerGuid}"
                                        LayerColor="{Binding LayerHighlightColor}"
                                        LayerIndex="{Binding ContainerIndex, ElementName=layerStructureContainer}"

+ 12 - 0
PixiEditor/Views/UserControls/PlainLayerView.xaml

@@ -0,0 +1,12 @@
+<UserControl x:Class="PixiEditor.Views.UserControls.PlainLayerView"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             xmlns:local="clr-namespace:PixiEditor.Views.UserControls"
+             mc:Ignorable="d" 
+             x:Name="uc"
+             d:DesignHeight="450" d:DesignWidth="800">
+    <Image x:Name="image" Width="{Binding Width, ElementName=uc}" Height="{Binding Height, ElementName=uc}" 
+           RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Uniform"/>
+</UserControl>

+ 105 - 0
PixiEditor/Views/UserControls/PlainLayerView.xaml.cs

@@ -0,0 +1,105 @@
+using PixiEditor.Models.Controllers;
+using PixiEditor.Models.Layers;
+using System;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace PixiEditor.Views.UserControls
+{
+    public partial class PlainLayerView : UserControl
+    {
+        public static readonly DependencyProperty TargetLayerProperty =
+            DependencyProperty.Register(nameof(TargetLayer), typeof(Layer), typeof(PlainLayerView), new PropertyMetadata(null, OnLayerChanged));
+
+        public Layer TargetLayer
+        {
+            get => (Layer)GetValue(TargetLayerProperty);
+            set => SetValue(TargetLayerProperty, value);
+        }
+
+        private SurfaceRenderer renderer;
+
+        public PlainLayerView()
+        {
+            InitializeComponent();
+            SizeChanged += OnControlSizeChanged;
+            Unloaded += OnControlUnloaded;
+        }
+
+        private static void OnLayerChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
+        {
+            var view = (PlainLayerView)sender;
+            if (args.OldValue != null)
+                ((Layer)args.OldValue).LayerBitmapChanged -= view.OnLayerBitmapChanged;
+            if (args.NewValue != null)
+            {
+                var layer = ((Layer)args.NewValue);
+                layer.LayerBitmapChanged += view.OnLayerBitmapChanged;
+                view.Resize(layer.Width, layer.Height);
+            }
+        }
+        public void Resize(int newWidth, int newHeight)
+        {
+            renderer?.Dispose();
+            renderer = new SurfaceRenderer(newWidth, newHeight);
+            image.Source = renderer.FinalBitmap;
+            Update();
+        }
+
+        private void Update()
+        {
+            renderer.Draw(TargetLayer.LayerBitmap, (byte)(TargetLayer.Opacity * 255));
+        }
+
+        private void OnControlUnloaded(object sender, RoutedEventArgs e)
+        {
+            /*
+            if (LogicalTreeHelper.GetParent(this) != null)
+                return;
+            renderer?.Dispose();
+            TargetLayer.LayerBitmapChanged -= OnLayerBitmapChanged;*/
+        }
+
+        private void OnControlSizeChanged(object sender, SizeChangedEventArgs e)
+        {
+            if (TargetLayer == null)
+                return;
+            MaybeResize(e.NewSize);
+        }
+
+        private bool MaybeResize(Size newSize)
+        {
+            var (w, h) = GetOptimizedDimensions(TargetLayer.Width, TargetLayer.Height, newSize.Width, newSize.Height);
+            Resize(w, h);
+            return true;
+        }
+
+        private (int, int) GetOptimizedDimensions(int width, int height, double viewWidth, double viewHeight)
+        {
+            if (width <= viewWidth && height <= viewHeight)
+                return (width, height);
+
+            double frac = width / (double)height;
+            double viewFrac = viewWidth / viewHeight;
+
+            if (frac > viewFrac)
+            {
+                double targetWidth = viewWidth;
+                double targetHeight = viewWidth / frac;
+                return ((int)Math.Ceiling(targetWidth), (int)Math.Ceiling(targetHeight));
+            }
+            else
+            {
+                double targetHeight = viewHeight;
+                double targetWidth = targetHeight * frac;
+                return ((int)Math.Ceiling(targetWidth), (int)Math.Ceiling(targetHeight));
+            }
+        }
+
+        private void OnLayerBitmapChanged(object sender, Int32Rect e)
+        {
+            if (!MaybeResize(RenderSize))
+                Update();
+        }
+    }
+}