Jelajahi Sumber

Merge branch 'feature/refrence-layer'

# Conflicts:
#	PixiEditor.ChangeableDocument/Changeables/Document.cs
#	PixiEditorPrototype/ViewModels/DocumentViewModel.cs
#	PixiEditorPrototype/Views/MainWindow.xaml
Equbuxu 3 tahun lalu
induk
melakukan
d94a7b17f6

+ 13 - 0
src/.idea/.idea.PixiEditorPrototype/.idea/.gitignore

@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/.idea.PixiEditorPrototype.iml
+/modules.xml
+/projectSettingsUpdater.xml
+/contentModel.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 262 - 0
src/.idea/.idea.PixiEditorPrototype/.idea/deployment.xml

@@ -0,0 +1,262 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="PublishConfigData">
+    <serverData>
+      <paths name="Pi">
+        <serverdata>
+          <mappings>
+            <mapping local="$PROJECT_DIR$/../../../../../../Program Files/dotnet/sdk/6.0.300/Sdks/Microsoft.NET.Sdk/analyzers/build/config/analysislevel_6_default.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/../../../../../../Program Files/dotnet/sdk/6.0.300/Sdks/Microsoft.NET.Sdk/analyzers/build/config/analysislevel_6_default.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/../../../../../../Program Files/dotnet/sdk/6.0.300/Sdks/Microsoft.NET.Sdk/analyzers/build/config/analysislevel_6_default.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/../../../../../../Program Files/dotnet/sdk/6.0.300/Sdks/Microsoft.NET.Sdk/analyzers/build/config/analysislevel_6_default.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/../../../../../../Program Files/dotnet/sdk/6.0.300/Sdks/Microsoft.NET.Sdk/analyzers/build/config/analysislevel_6_default.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/../../../../../../Program Files/dotnet/sdk/6.0.300/Sdks/Microsoft.NET.Sdk/analyzers/build/config/analysislevel_6_default.editorconfig" web="/" />
+            <mapping local="$USER_HOME$/.nuget/packages/microsoft.net.test.sdk/16.11.0/build/netcoreapp2.1/Microsoft.NET.Test.Sdk.Program.cs" web="/" />
+            <mapping local="$USER_HOME$/.nuget/packages/microsoft.testplatform.testhost/16.11.0/build/netcoreapp2.1/x64/Microsoft.TestPlatform.PlatformAbstractions.dll" web="/" />
+            <mapping local="$USER_HOME$/.nuget/packages/microsoft.testplatform.testhost/16.11.0/build/netcoreapp2.1/x64/testhost.dll" web="/" />
+            <mapping local="$USER_HOME$/.nuget/packages/microsoft.testplatform.testhost/16.11.0/build/netcoreapp2.1/x64/testhost.exe" web="/" />
+            <mapping local="$USER_HOME$/.nuget/packages/xunit.runner.visualstudio/2.4.3/build/netcoreapp2.1/xunit.runner.reporters.netcoreapp10.dll" web="/" />
+            <mapping local="$USER_HOME$/.nuget/packages/xunit.runner.visualstudio/2.4.3/build/netcoreapp2.1/xunit.runner.utility.netcoreapp10.dll" web="/" />
+            <mapping local="$USER_HOME$/.nuget/packages/xunit.runner.visualstudio/2.4.3/build/netcoreapp2.1/xunit.runner.visualstudio.dotnetcore.testadapter.dll" web="/" />
+            <mapping local="$PROJECT_DIR$/.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Chunk.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/ChunkPool.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/ChunkyImage.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/ChunkyImageEx.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/ChunkyImageLib.csproj" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/CommittedChunkStorage.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/DataHolders/ChunkResolution.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/DataHolders/ChunkResolutionEx.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/DataHolders/EmptyChunk.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/DataHolders/FilledChunk.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/DataHolders/RectD.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/DataHolders/RectI.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/DataHolders/ShapeCorners.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/DataHolders/ShapeData.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/DataHolders/VecD.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/DataHolders/VecI.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/IReadOnlyChunkyImage.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/BresenhamLineHelper.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/BresenhamLineOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/ChunkyImageOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/ClearOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/ClearRegionOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/EllipseHelper.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/EllipseOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/IDrawOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/IOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/ImageOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/OperationHelper.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/PathOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/RectangleOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/ResizeOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Operations/SkiaLineOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/Surface.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/obj/Debug/net6.0/ChunkyImageLib.AssemblyInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/obj/Debug/net6.0/ChunkyImageLib.GeneratedMSBuildEditorConfig.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLib/obj/Debug/net6.0/ChunkyImageLib.GlobalUsings.g.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibTest/ChunkyImageLibTest.csproj" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibTest/ChunkyImageTests.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibTest/ClearRegionOperationTests.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibTest/ImageOperationTests.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibTest/OperationHelperTests.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibTest/RectITests.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibTest/RectangleOperationTests.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibTest/obj/Debug/net6.0/ChunkyImageLibTest.AssemblyInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibTest/obj/Debug/net6.0/ChunkyImageLibTest.GeneratedMSBuildEditorConfig.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibVis/App.xaml" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibVis/App.xaml.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibVis/AssemblyInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibVis/ChunkyImageLibVis.csproj" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibVis/MainWindow.xaml" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibVis/MainWindow.xaml.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibVis/obj/Debug/net6.0-windows/App.g.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibVis/obj/Debug/net6.0-windows/ChunkyImageLibVis.AssemblyInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibVis/obj/Debug/net6.0-windows/ChunkyImageLibVis.GeneratedMSBuildEditorConfig.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/ChunkyImageLibVis/obj/Debug/net6.0-windows/MainWindow.g.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/bin/Debug/netstandard2.0/PixiEditor.ChangeableDocument.Gen.dll" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/ChangeActionGenerator.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/Helpers.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/MethodInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/NamedSourceCode.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/NamespacedType.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/PixiEditor.ChangeableDocument.Gen.csproj" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/Result.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/TypeWithName.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/UpdateableChangeActionGenerator.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/obj/Debug/netstandard2.0/PixiEditor.ChangeableDocument.Gen.AssemblyInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/obj/Debug/netstandard2.0/PixiEditor.ChangeableDocument.Gen.GeneratedMSBuildEditorConfig.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument.Gen/obj/Debug/netstandard2.0/PixiEditor.ChangeableDocument.Gen.GlobalUsings.g.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Actions/Attributes/GenerateMakeChangeActionAttribute.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Actions/Attributes/GenerateUpdateableChangeActionsAttribute.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Actions/Attributes/UpdateChangeMethodAttribute.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Actions/IAction.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Actions/IEndChangeAction.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Actions/IMakeChangeAction.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Actions/IStartOrUpdateChangeAction.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Actions/Undo/ChangeBoundary_Action.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Actions/Undo/DeleteRecordedChanges_Action.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Actions/Undo/Redo_Action.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Actions/Undo/Undo_Action.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Drawing/LayerImageChunks_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Drawing/MaskChunks_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Drawing/Selection_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/IChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Properties/LayerLockTransparency_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Properties/StructureMemberBlendMode_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Properties/StructureMemberClipToMemberBelow_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Properties/StructureMemberIsVisible_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Properties/StructureMemberMaskIsVisible_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Properties/StructureMemberMask_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Properties/StructureMemberName_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Properties/StructureMemberOpacity_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Root/Size_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Root/SymmetryAxisPosition_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Root/SymmetryAxisState_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Structure/CreateFolder_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Structure/CreateLayer_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Structure/CreateStructureMember_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Structure/DeleteStructureMember_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/ChangeInfos/Structure/MoveStructureMember_ChangeInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changeables/Document.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changeables/Folder.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changeables/IChangeable.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyDocument.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyFolder.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyLayer.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlySelection.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyStructureMember.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changeables/Layer.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changeables/Selection.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changeables/StructureMember.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/ApplyLayerMask_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/ClearSelectedArea_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/ClearSelection_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/CombineStructureMembersOnto_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/DrawEllipse_UpdateableChange.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/DrawRectangle_UpdateableChange.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/DrawingChangeHelper.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillChunkStorage.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillColorBounds.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillHelper.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFill_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/LineBasedPen_UpdateableChange.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/PasteImage_UpdateableChange.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/PathBasedPen_UpdateableChange.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Drawing/ShiftLayer_UpdateableChange.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Properties/CreateStructureMemberMask_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Properties/DeleteStructureMemberMask_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Properties/LayerLockTransparency_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Properties/StructureMemberBlendMode_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Properties/StructureMemberClipToMemberBelow_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Properties/StructureMemberIsVisible_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Properties/StructureMemberMaskIsVisible_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Properties/StructureMemberName_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Properties/StructureMemberOpacity_UpdateableChange.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Root/ResizeCanvas_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Root/SymmetryAxisPosition_UpdateableChange.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Root/SymmetryAxisState_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Selection/SelectLasso_UpdateableChange.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Selection/SelectRectangle_UpdateableChange.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Selection/TransformSelectionPath_UpdateableChange.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Structure/CreateStructureMember_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Structure/DeleteStructureMember_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/Structure/MoveStructureMember_Change.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Changes/UpdateableChange.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/DocumentChangeTracker.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Enums/BlendMode.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Enums/SelectionMode.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Enums/SelectionModeEx.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Enums/StructureMemberType.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Enums/SymmetryAxisDirection.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/GlobalUsings.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/PixiEditor.ChangeableDocument.csproj" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Rendering/ChunkRenderer.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/Rendering/RenderingContext.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/obj/Debug/net6.0/PixiEditor.ChangeableDocument.AssemblyInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/obj/Debug/net6.0/PixiEditor.ChangeableDocument.GeneratedMSBuildEditorConfig.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.ChangeableDocument/obj/Debug/net6.0/PixiEditor.ChangeableDocument.GlobalUsings.g.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/AssemblyInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/IDragOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/MoveDragOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/PixiEditor.Zoombox.csproj" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/RotateDragOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/ViewportRoutedEventArgs.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/ZoomDragOperation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/Zoombox.xaml" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/Zoombox.xaml.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/ZoomboxMode.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/obj/Debug/net6.0-windows/PixiEditor.Zoombox.AssemblyInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/obj/Debug/net6.0-windows/PixiEditor.Zoombox.GeneratedMSBuildEditorConfig.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditor.Zoombox/obj/Debug/net6.0-windows/Zoombox.g.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype.sln" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/App.xaml" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/App.xaml.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/AssemblyInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Behaviors/SliderUpdateBehavior.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Converters/BlendModeToStringConverter.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Converters/BoolToVisibilityConverter.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Converters/IndexToChunkResolutionConverter.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Converters/ScaleToBitmapScalingModeConverter.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/CustomControls/BlendModeComboBox.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/CustomControls/SelectionOverlay.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/CustomControls/SymmetryOverlay/SymmetryAxisDragInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/CustomControls/SymmetryOverlay/SymmetryOverlay.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/CustomControls/TransformOverlay/Anchor.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/CustomControls/TransformOverlay/TransformCornerFreedom.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/CustomControls/TransformOverlay/TransformHelper.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/CustomControls/TransformOverlay/TransformOverlay.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/CustomControls/TransformOverlay/TransformSideFreedom.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/CustomControls/TransformOverlay/TransformState.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/CustomControls/TransformOverlay/TransformUpdateHelper.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/GlobalUsings.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/ActionAccumulator.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/BlendModeEx.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/DocumentHelpers.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/DocumentState.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/DocumentStructureHelper.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/DocumentUpdater.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/IReadOnlyListEx.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/RefreshViewport_PassthroughAction.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/RemoveViewport_PassthroughAction.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/Rendering/AffectedChunkGatherer.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/Rendering/RenderInfos/DirtyRect_RenderInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/Rendering/RenderInfos/IRenderInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/Rendering/RenderInfos/MaskPreviewDirty_RenderInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/Rendering/RenderInfos/PreviewDirty_RenderInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/Rendering/WriteableBitmapUpdater.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/Tool.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Models/ViewportLocation.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/PixiEditorPrototype.csproj" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/RelayCommand.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/ReverseOrderStackPanel.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/UserControls/Viewport/Viewport.xaml" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/UserControls/Viewport/Viewport.xaml.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/ViewModels/DocumentTransformViewModel.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/ViewModels/DocumentViewModel.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/ViewModels/FolderViewModel.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/ViewModels/LayerViewModel.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/ViewModels/StructureMemberViewModel.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/ViewModels/ViewModelMain.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Views/MainWindow.xaml" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/Views/MainWindow.xaml.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/obj/Debug/net6.0-windows/App.g.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/obj/Debug/net6.0-windows/GeneratedInternalTypeHelper.g.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/obj/Debug/net6.0-windows/PixiEditorPrototype.AssemblyInfo.cs" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/obj/Debug/net6.0-windows/PixiEditorPrototype.GeneratedMSBuildEditorConfig.editorconfig" web="/" />
+            <mapping local="$PROJECT_DIR$/PixiEditorPrototype/obj/Debug/net6.0-windows/Views/MainWindow.g.cs" web="/" />
+            <mapping local="$PROJECT_DIR$" web="/" />
+          </mappings>
+        </serverdata>
+      </paths>
+    </serverData>
+  </component>
+</project>

+ 8 - 0
src/.idea/.idea.PixiEditorPrototype/.idea/indexLayout.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="UserContentModel">
+    <attachedFolders />
+    <explicitIncludes />
+    <explicitExcludes />
+  </component>
+</project>

+ 5 - 5
src/ChunkyImageLib/Surface.cs

@@ -8,9 +8,9 @@ namespace ChunkyImageLib;
 public class Surface : IDisposable
 {
     private bool disposed;
-    private int bytesPerPixel;
     public IntPtr PixelBuffer { get; }
     public SKSurface SkiaSurface { get; }
+    public int BytesPerPixel { get; }
     public VecI Size { get; }
 
     private SKPaint drawingPaint = new SKPaint() { BlendMode = SKBlendMode.Src };
@@ -24,8 +24,8 @@ public class Surface : IDisposable
 
         Size = size;
 
-        bytesPerPixel = 8;
-        PixelBuffer = CreateBuffer(size.X, size.Y, bytesPerPixel);
+        BytesPerPixel = 8;
+        PixelBuffer = CreateBuffer(size.X, size.Y, BytesPerPixel);
         SkiaSurface = CreateSKSurface();
     }
 
@@ -50,7 +50,7 @@ public class Surface : IDisposable
     {
         if (other.Size != Size)
             throw new ArgumentException("Target Surface must have the same dimensions");
-        int bytesC = Size.X * Size.Y * bytesPerPixel;
+        int bytesC = Size.X * Size.Y * BytesPerPixel;
         using var pixmap = other.SkiaSurface.PeekPixels();
         Buffer.MemoryCopy((void*)PixelBuffer, (void*)pixmap.GetPixels(), bytesC, bytesC);
     }
@@ -60,7 +60,7 @@ public class Surface : IDisposable
     /// </summary>
     public unsafe SKColor GetSRGBPixel(VecI pos)
     {
-        Half* ptr = (Half*)(PixelBuffer + (pos.X + pos.Y * Size.X) * bytesPerPixel);
+        Half* ptr = (Half*)(PixelBuffer + (pos.X + pos.Y * Size.X) * BytesPerPixel);
         float a = (float)ptr[3];
         return (SKColor)new SKColorF((float)ptr[0] / a, (float)ptr[1] / a, (float)ptr[2] / a, (float)ptr[3]);
     }

+ 18 - 7
src/PixiEditor.ChangeableDocument.Gen/Helpers.cs

@@ -14,20 +14,23 @@ internal static class Helpers
         List<TypeWithName> constructorArgs = changeConstructorInfo.Arguments;
         List<TypeWithName> properties = constructorArgs.Select(static typeWithName =>
             {
-                return new TypeWithName(typeWithName.Type, typeWithName.FullNamespace, VariableNameIntoPropertyName(typeWithName.Name));
+                return new TypeWithName(typeWithName.Type, typeWithName.FullNamespace, VariableNameIntoPropertyName(typeWithName.Name), typeWithName.Nullable);
             }).ToList();
 
         var propToVar = MatchMembers(properties, constructorArgs);
 
         StringBuilder sb = new();
-
-        sb.AppendLine("namespace PixiEditor.ChangeableDocument.Actions.Generated;");
+         
+        sb.AppendLine("namespace PixiEditor.ChangeableDocument.Actions.Generated;\n");
+        sb.AppendLine("[System.Runtime.CompilerServices.CompilerGenerated]");
         sb.AppendLine($"public record class {actionName} : PixiEditor.ChangeableDocument.Actions.IMakeChangeAction");
         sb.AppendLine("{");
         sb.Append($"public {actionName}");
         AppendArgumentList(sb, constructorArgs);
         AppendConstructorBody(sb, propToVar);
+        sb.AppendLine("// Properties");
         AppendProperties(sb, properties);
+        sb.AppendLine("// Changes");
         AppendCreateCorrespondingChange(sb, changeConstructorInfo.ContainingClass, properties);
         sb.AppendLine("}");
 
@@ -41,7 +44,7 @@ internal static class Helpers
         List<TypeWithName> constructorArgs = changeConstructorInfo.Arguments;
         List<TypeWithName> properties = constructorArgs.Select(static typeWithName =>
         {
-            return new TypeWithName(typeWithName.Type, typeWithName.FullNamespace, VariableNameIntoPropertyName(typeWithName.Name));
+            return new TypeWithName(typeWithName.Type, typeWithName.FullNamespace, VariableNameIntoPropertyName(typeWithName.Name), typeWithName.Nullable);
         }).ToList();
 
         var constructorAssignments = MatchMembers(properties, constructorArgs);
@@ -94,7 +97,8 @@ public record class {actionName} : PixiEditor.ChangeableDocument.Actions.IEndCha
             return new TypeWithName(
                 parameter.Type.ToDisplayString(TypeWithGenerics),
                 parameter.Type.ContainingNamespace.ToDisplayString(),
-                parameter.Name
+                parameter.Name,
+                parameter.NullableAnnotation is NullableAnnotation.Annotated
                 );
         }).ToList();
         string changeName = method.ContainingType.Name;
@@ -136,7 +140,14 @@ public record class {actionName} : PixiEditor.ChangeableDocument.Actions.IEndCha
         sb.Append("(");
         for (int i = 0; i < variables.Count; i++)
         {
-            sb.Append(variables[i].TypeWithNamespace).Append(" ").Append(variables[i].Name);
+            sb.Append(variables[i].TypeWithNamespace);
+
+            if (variables[i].Nullable)
+            {
+                sb.Append("?");
+            }
+            
+            sb.Append(" ").Append(variables[i].Name);
             if (i != variables.Count - 1)
                 sb.Append(", ");
         }
@@ -195,7 +206,7 @@ public record class {actionName} : PixiEditor.ChangeableDocument.Actions.IEndCha
     {
         foreach (var typeWithName in properties)
         {
-            sb.AppendLine($"public {typeWithName.TypeWithNamespace} {typeWithName.Name} {{ get; init; }}");
+            sb.AppendLine($"public {typeWithName.TypeWithNamespace}{(typeWithName.Nullable ? "?" : "")} {typeWithName.Name} {{ get; init; }}");
         }
     }
 

+ 3 - 1
src/PixiEditor.ChangeableDocument.Gen/TypeWithName.cs

@@ -1,15 +1,17 @@
 namespace PixiEditor.ChangeableDocument.Gen;
 internal struct TypeWithName
 {
-    public TypeWithName(string type, string fullNamespace, string name)
+    public TypeWithName(string type, string fullNamespace, string name, bool nullable)
     {
         Type = type;
         FullNamespace = fullNamespace;
         Name = name;
+        Nullable = nullable;
     }
 
     public string Type { get; }
     public string FullNamespace { get; }
     public string TypeWithNamespace => FullNamespace + "." + Type;
     public string Name { get; }
+    public bool Nullable { get; }
 }

+ 3 - 0
src/PixiEditor.ChangeableDocument/ChangeInfos/Structure/CreateReferenceLayer_ChangeInfo.cs

@@ -0,0 +1,3 @@
+namespace PixiEditor.ChangeableDocument.ChangeInfos.Structure;
+
+public record class CreateReferenceLayer_ChangeInfo(bool ShapeOnly) : IChangeInfo;

+ 3 - 0
src/PixiEditor.ChangeableDocument/ChangeInfos/Structure/TransformReferenceLayer_ChangeInfo.cs

@@ -0,0 +1,3 @@
+namespace PixiEditor.ChangeableDocument.ChangeInfos.Structure;
+
+public record class TransformReferenceLayer_ChangeInfo(ShapeCorners Shape) : IChangeInfo;

+ 3 - 0
src/PixiEditor.ChangeableDocument/Changeables/Document.cs

@@ -13,12 +13,15 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
     IReadOnlyStructureMember IReadOnlyDocument.FindMemberOrThrow(Guid guid) => FindMemberOrThrow(guid);
     (IReadOnlyStructureMember, IReadOnlyFolder) IReadOnlyDocument.FindChildAndParentOrThrow(Guid guid) => FindChildAndParentOrThrow(guid);
 
+    IReadOnlyReferenceLayer? IReadOnlyDocument.ReferenceLayer => ReferenceLayer;
     /// <summary>
     /// The default size for a new document
     /// </summary>
+
     public static VecI DefaultSize { get; } = new VecI(64, 64);
     internal Folder StructureRoot { get; } = new() { GuidValue = Guid.Empty };
     internal Selection Selection { get; } = new();
+    internal ReferenceLayer? ReferenceLayer { get; set; }
     public VecI Size { get; set; } = DefaultSize;
     public bool HorizontalSymmetryAxisEnabled { get; set; }
     public bool VerticalSymmetryAxisEnabled { get; set; }

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyDocument.cs

@@ -72,4 +72,5 @@ public interface IReadOnlyDocument
     /// </summary>
     /// <param name="guid">The <see cref="IReadOnlyStructureMember.GuidValue"/> of the member</param>
     IReadOnlyList<IReadOnlyStructureMember> FindMemberPath(Guid guid);
+    IReadOnlyReferenceLayer? ReferenceLayer { get; }
 }

+ 10 - 0
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyReferenceLayer.cs

@@ -0,0 +1,10 @@
+using SkiaSharp;
+
+namespace PixiEditor.ChangeableDocument.Changeables.Interfaces;
+
+public interface IReadOnlyReferenceLayer
+{
+    public Surface Image { get; }
+    
+    public ShapeCorners Shape { get; }
+}

+ 17 - 0
src/PixiEditor.ChangeableDocument/Changeables/ReferenceLayer.cs

@@ -0,0 +1,17 @@
+using PixiEditor.ChangeableDocument.Changeables.Interfaces;
+using SkiaSharp;
+
+namespace PixiEditor.ChangeableDocument.Changeables;
+
+public class ReferenceLayer : IReadOnlyReferenceLayer
+{
+    public Surface Image { get; }
+    
+    public ShapeCorners Shape { get; set; }
+
+    public ReferenceLayer(Surface image, ShapeCorners shape)
+    {
+        Image = image;
+        Shape = shape;
+    }
+}

+ 51 - 0
src/PixiEditor.ChangeableDocument/Changes/Root/CreateReferenceLayer_UpdateableChange.cs

@@ -0,0 +1,51 @@
+using PixiEditor.ChangeableDocument.ChangeInfos.Structure;
+
+namespace PixiEditor.ChangeableDocument.Changes.Root;
+
+internal class CreateReferenceLayer_UpdateableChange : UpdateableChange
+{
+    private readonly Surface? surface;
+    private ShapeCorners shape;
+
+    [GenerateUpdateableChangeActions]
+    public CreateReferenceLayer_UpdateableChange(Surface? surface, ShapeCorners shape)
+    {
+        this.surface = surface;
+        this.shape = shape;
+    }
+
+    [UpdateChangeMethod]
+    public void Update(ShapeCorners shape)
+    {
+        this.shape = shape;
+    }
+
+    public override OneOf<Success, Error> InitializeAndValidate(Document target)
+    {
+        if (surface is null)
+        {
+            return new Error();
+        }
+
+        target.ReferenceLayer = new ReferenceLayer(surface!, shape);
+        return new Success();
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, out bool ignoreInUndo)
+    {
+        target.ReferenceLayer!.Shape = shape;
+        ignoreInUndo = true;
+        return new CreateReferenceLayer_ChangeInfo(true);
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
+    {
+        throw new NotImplementedException();
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> ApplyTemporarily(Document target)
+    {
+        target.ReferenceLayer!.Shape = shape;
+        return new CreateReferenceLayer_ChangeInfo(true);
+    }
+}

+ 42 - 0
src/PixiEditorPrototype/Helpers/SurfaceHelpers.cs

@@ -0,0 +1,42 @@
+using System;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using ChunkyImageLib;
+using SkiaSharp;
+
+namespace PixiEditorPrototype.Helpers;
+
+public static class SurfaceHelpers
+{
+    public static WriteableBitmap ToWriteableBitmap(this Surface surface)
+    {
+        int width = surface.Size.X;
+        int height = surface.Size.Y;
+        WriteableBitmap result = new WriteableBitmap(width, height, 96, 96, PixelFormats.Pbgra32, null);
+        result.Lock();
+        var dirty = new Int32Rect(0, 0, width, height);
+        result.WritePixels(dirty, ToByteArray(surface), width * 4, 0);
+        result.AddDirtyRect(dirty);
+        result.Unlock();
+        return result;
+    }
+
+    private static unsafe byte[] ToByteArray(Surface surface, SKColorType colorType = SKColorType.Bgra8888, SKAlphaType alphaType = SKAlphaType.Premul)
+    {
+        int width = surface.Size.X;
+        int height = surface.Size.Y;
+        var imageInfo = new SKImageInfo(width, height, colorType, alphaType, SKColorSpace.CreateSrgb());
+
+        byte[] buffer = new byte[width * height * imageInfo.BytesPerPixel];
+        fixed (void* pointer = buffer)
+        {
+            if (!surface.SkiaSurface.ReadPixels(imageInfo, new IntPtr(pointer), imageInfo.RowBytes, 0, 0))
+            {
+                throw new InvalidOperationException("Could not read surface into buffer");
+            }
+        }
+
+        return buffer;
+    }
+}

+ 12 - 0
src/PixiEditorPrototype/Models/DocumentUpdater.cs

@@ -86,9 +86,21 @@ internal class DocumentUpdater
             case StructureMemberMaskIsVisible_ChangeInfo info:
                 ProcessMaskIsVisible(info);
                 break;
+            case CreateReferenceLayer_ChangeInfo info:
+                ProcessCreateReferenceLayer(info);
+                break;
         }
     }
 
+    private void ProcessCreateReferenceLayer(CreateReferenceLayer_ChangeInfo info)
+    {
+        doc.RaisePropertyChanged(nameof(doc.ReferenceLayer));
+        doc.RaisePropertyChanged(nameof(doc.ReferenceBitmap));
+        doc.RaisePropertyChanged(nameof(doc.ReferenceBitmapSize));
+        doc.RaisePropertyChanged(nameof(doc.ReferenceTransformMatrix));
+        doc.RaisePropertyChanged(nameof(doc.ReferenceShape));
+    }
+
     private void ProcessMaskIsVisible(StructureMemberMaskIsVisible_ChangeInfo info)
     {
         var member = helper.StructureHelper.FindOrThrow(info.GuidValue);

+ 8 - 0
src/PixiEditorPrototype/PixiEditorPrototype.csproj

@@ -8,6 +8,14 @@
     <WarningsAsErrors>Nullable</WarningsAsErrors>
   </PropertyGroup>
 
+  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+
   <ItemGroup>
     <PackageReference Include="Dirkster.AvalonDock" Version="4.70.1" />
     <PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />

+ 95 - 47
src/PixiEditorPrototype/UserControls/Viewport/Viewport.xaml

@@ -1,88 +1,136 @@
-<UserControl x:Class="PixiEditorPrototype.UserControls.Viewport.Viewport"
-             x:ClassModifier="internal"
-             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:PixiEditorPrototype.UserControls.Viewport"
-             xmlns:zoombox="clr-namespace:PixiEditor.Zoombox;assembly=PixiEditor.Zoombox"
-             xmlns:to="clr-namespace:PixiEditorPrototype.CustomControls.TransformOverlay"
-             xmlns:cust="clr-namespace:PixiEditorPrototype.CustomControls"
-             xmlns:sym="clr-namespace:PixiEditorPrototype.CustomControls.SymmetryOverlay"
-             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
-             xmlns:conv="clr-namespace:PixiEditorPrototype.Converters"
-             mc:Ignorable="d"
-             x:Name="vpUc"
-             d:DesignHeight="450" d:DesignWidth="800">
+<UserControl
+    x:Class="PixiEditorPrototype.UserControls.Viewport.Viewport"
+    x:ClassModifier="internal"
+    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:PixiEditorPrototype.UserControls.Viewport"
+    xmlns:zoombox="clr-namespace:PixiEditor.Zoombox;assembly=PixiEditor.Zoombox"
+    xmlns:to="clr-namespace:PixiEditorPrototype.CustomControls.TransformOverlay"
+    xmlns:cust="clr-namespace:PixiEditorPrototype.CustomControls"
+    xmlns:sym="clr-namespace:PixiEditorPrototype.CustomControls.SymmetryOverlay"
+    xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
+    xmlns:conv="clr-namespace:PixiEditorPrototype.Converters"
+    mc:Ignorable="d"
+    x:Name="vpUc"
+    d:DesignHeight="450"
+    d:DesignWidth="800">
     <UserControl.Resources>
-        <conv:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
-        <conv:ScaleToBitmapScalingModeConverter x:Key="ScaleToBitmapScalingModeConverter"/>
+        <conv:BoolToVisibilityConverter
+            x:Key="BoolToVisibilityConverter" />
+        <conv:ScaleToBitmapScalingModeConverter
+            x:Key="ScaleToBitmapScalingModeConverter" />
     </UserControl.Resources>
     <Grid>
-        <zoombox:Zoombox 
-            x:Name="zoombox" UseTouchGestures="True"
+        <zoombox:Zoombox
+            x:Name="zoombox"
+            UseTouchGestures="True"
+            Scale="{Binding ZoomboxScale, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:Viewport}, Mode=OneWayToSource}"
             Center="{Binding Center, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:Viewport}, Mode=OneWayToSource}"
             Angle="{Binding Angle, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:Viewport}, Mode=OneWayToSource}"
             RealDimensions="{Binding RealDimensions, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:Viewport}, Mode=OneWayToSource}"
             Dimensions="{Binding Dimensions, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:Viewport}, Mode=OneWayToSource}"
-            ZoomMode="{Binding ZoomMode, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:Viewport}, Mode=TwoWay}" 
+            ZoomMode="{Binding ZoomMode, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:Viewport}, Mode=TwoWay}"
             FlipX="{Binding FlipX, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:Viewport}}"
             FlipY="{Binding FlipY, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:Viewport}}">
-            <Border 
-                BorderThickness="1" Background="White" BorderBrush="Black" HorizontalAlignment="Center" VerticalAlignment="Center"
+            <Border
+                BorderThickness="1"
+                Background="White"
+                BorderBrush="Black"
+                HorizontalAlignment="Center"
+                VerticalAlignment="Center"
                 DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:Viewport}}">
                 <Grid>
-                    <Image 
+                    <Canvas>
+                        <Image
+                            Width="{Binding Document.ReferenceBitmap.Width}"
+                            Height="{Binding Document.ReferenceBitmap.Height}"
+                            Source="{Binding Document.ReferenceBitmap, Mode=OneWay}"
+                            SizeChanged="OnReferenceImageSizeChanged"
+                            RenderOptions.BitmapScalingMode="{Binding ReferenceLayerScale, Converter={StaticResource ScaleToBitmapScalingModeConverter}}">
+                            <Image.RenderTransform>
+                                <TransformGroup>
+                                    <MatrixTransform
+                                        Matrix="{Binding Document.ReferenceTransformMatrix}" />
+                                </TransformGroup>
+                            </Image.RenderTransform>
+                        </Image>
+                    </Canvas>
+                    <Image
                         Focusable="True"
-                        Width="{Binding Document.Width}" Height="{Binding Document.Height}"
+                        Width="{Binding Document.Width}"
+                        Height="{Binding Document.Height}"
                         Source="{Binding TargetBitmap}"
                         RenderOptions.BitmapScalingMode="{Binding Zoombox.Scale, Converter={StaticResource ScaleToBitmapScalingModeConverter}}">
                         <i:Interaction.Triggers>
-                            <i:EventTrigger EventName="MouseDown">
-                                <i:InvokeCommandAction Command="{Binding MouseDownCommand}" PassEventArgsToCommand="True"/>
+                            <i:EventTrigger
+                                EventName="MouseDown">
+                                <i:InvokeCommandAction
+                                    Command="{Binding MouseDownCommand}"
+                                    PassEventArgsToCommand="True" />
                             </i:EventTrigger>
-                            <i:EventTrigger EventName="MouseMove">
-                                <i:InvokeCommandAction Command="{Binding MouseMoveCommand}" PassEventArgsToCommand="True"/>
+                            <i:EventTrigger
+                                EventName="MouseMove">
+                                <i:InvokeCommandAction
+                                    Command="{Binding MouseMoveCommand}"
+                                    PassEventArgsToCommand="True" />
                             </i:EventTrigger>
-                            <i:EventTrigger EventName="MouseUp">
-                                <i:InvokeCommandAction Command="{Binding MouseUpCommand}" PassEventArgsToCommand="True"/>
+                            <i:EventTrigger
+                                EventName="MouseUp">
+                                <i:InvokeCommandAction
+                                    Command="{Binding MouseUpCommand}"
+                                    PassEventArgsToCommand="True" />
                             </i:EventTrigger>
                         </i:Interaction.Triggers>
                     </Image>
-                    <sym:SymmetryOverlay 
+                    <sym:SymmetryOverlay
                         ZoomboxScale="{Binding Zoombox.Scale}"
                         HorizontalAxisVisible="{Binding Document.HorizontalSymmetryAxisEnabledBindable}"
                         VerticalAxisVisible="{Binding Document.VerticalSymmetryAxisEnabledBindable}"
                         HorizontalAxisY="{Binding Document.HorizontalSymmetryAxisYBindable, Mode=OneWay}"
                         VerticalAxisX="{Binding Document.VerticalSymmetryAxisXBindable, Mode=OneWay}"
                         DragCommand="{Binding Document.DragSymmetryCommand}"
-                        DragEndCommand="{Binding Document.EndDragSymmetryCommand}"
-                        />
-                    <cust:SelectionOverlay Path="{Binding Document.SelectionPathBindable}" ZoomboxScale="{Binding Zoombox.Scale}"/>
-                    <to:TransformOverlay 
-                        HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
+                        DragEndCommand="{Binding Document.EndDragSymmetryCommand}" />
+                    <cust:SelectionOverlay
+                        Path="{Binding Document.SelectionPathBindable}"
+                        ZoomboxScale="{Binding Zoombox.Scale}" />
+                    <to:TransformOverlay
+                        HorizontalAlignment="Stretch"
+                        VerticalAlignment="Stretch"
                         Visibility="{Binding Document.TransformViewModel.TransformActive, Converter={StaticResource BoolToVisibilityConverter}}"
                         Corners="{Binding Document.TransformViewModel.Corners, Mode=TwoWay}"
                         RequestedCorners="{Binding Document.TransformViewModel.RequestedCorners, Mode=TwoWay}"
                         CornerFreedom="{Binding Document.TransformViewModel.CornerFreedom}"
                         SideFreedom="{Binding Document.TransformViewModel.SideFreedom}"
                         InternalState="{Binding Document.TransformViewModel.InternalState, Mode=TwoWay}"
-                        ZoomboxScale="{Binding Zoombox.Scale}"/>
+                        ZoomboxScale="{Binding Zoombox.Scale}" />
                 </Grid>
             </Border>
         </zoombox:Zoombox>
-        <Grid Focusable="False">
+        <Grid
+            Focusable="False">
             <Grid.ColumnDefinitions>
-                <ColumnDefinition Width="1*"/>
-                <ColumnDefinition Width="2*"/>
-                <ColumnDefinition Width="1*"/>
+                <ColumnDefinition
+                    Width="1*" />
+                <ColumnDefinition
+                    Width="2*" />
+                <ColumnDefinition
+                    Width="1*" />
             </Grid.ColumnDefinitions>
             <Grid.RowDefinitions>
-                <RowDefinition Height="1*"/>
-                <RowDefinition Height="2*"/>
-                <RowDefinition Height="1*"/>
+                <RowDefinition
+                    Height="1*" />
+                <RowDefinition
+                    Height="2*" />
+                <RowDefinition
+                    Height="1*" />
             </Grid.RowDefinitions>
-            <Border BorderBrush="Red" Grid.Row="1" Grid.Column="1" BorderThickness="1"/>
+            <Border
+                BorderBrush="Red"
+                Grid.Row="1"
+                Grid.Column="1"
+                BorderThickness="1" />
         </Grid>
     </Grid>
-</UserControl>
+</UserControl>

+ 28 - 5
src/PixiEditorPrototype/UserControls/Viewport/Viewport.xaml.cs

@@ -36,7 +36,7 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
         DependencyProperty.Register(nameof(MouseMoveCommand), typeof(ICommand), typeof(Viewport), new(null));
 
     public static readonly DependencyProperty MouseUpCommandProperty =
-            DependencyProperty.Register(nameof(MouseUpCommand), typeof(ICommand), typeof(Viewport), new(null));
+        DependencyProperty.Register(nameof(MouseUpCommand), typeof(ICommand), typeof(Viewport), new(null));
 
     private static readonly DependencyProperty BitmapsProperty =
         DependencyProperty.Register(nameof(Bitmaps), typeof(Dictionary<ChunkResolution, WriteableBitmap>), typeof(Viewport), new(null, OnBitmapsChange));
@@ -87,6 +87,16 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
         set => SetValue(ZoomModeProperty, value);
     }
 
+    public double ZoomboxScale
+    {
+        get => zoombox.Scale;
+        // ReSharper disable once ValueParameterNotUsed
+        set
+        {
+            PropertyChanged?.Invoke(this, new(nameof(ReferenceLayerScale)));
+        }
+    }
+
     public bool FlipX
     {
         get => (bool)GetValue(FlipXProperty);
@@ -100,6 +110,7 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
     }
 
     private double angle = 0;
+
     public double Angle
     {
         get => angle;
@@ -112,6 +123,7 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
     }
 
     private VecD center = new(32, 32);
+
     public VecD Center
     {
         get => center;
@@ -124,6 +136,7 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
     }
 
     private VecD realDimensions = new(double.MaxValue, double.MaxValue);
+
     public VecD RealDimensions
     {
         get => realDimensions;
@@ -142,6 +155,7 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
     }
 
     private VecD dimensions = new(64, 64);
+
     public VecD Dimensions
     {
         get => dimensions;
@@ -167,6 +181,11 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
         }
     }
 
+    public double ReferenceLayerScale =>
+        ZoomboxScale * ((Document?.ReferenceBitmap != null)
+            ? (Document.ReferenceShape.RectSize.X / (double)Document.ReferenceBitmap.Width)
+            : 1);
+
     public Zoombox Zoombox => zoombox;
 
     public Guid GuidValue { get; } = Guid.NewGuid();
@@ -175,16 +194,15 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
     {
         InitializeComponent();
 
-        Binding binding = new Binding();
-        binding.Source = this;
-        binding.Path = new PropertyPath("Document.Bitmaps");
+        Binding binding = new Binding { Source = this, Path = new PropertyPath("Document.Bitmaps") };
         SetBinding(BitmapsProperty, binding);
 
         Loaded += OnLoad;
         Unloaded += OnUnload;
     }
 
-    private Image? GetImage() => (Image?)((Grid?)((Border?)zoombox.AdditionalContent)?.Child)?.Children[0];
+    private Image? GetImage() => (Image?)((Grid?)((Border?)zoombox.AdditionalContent)?.Child)?.Children[1];
+
     private void ForceRefreshFinalImage()
     {
         GetImage()?.InvalidateVisual();
@@ -231,4 +249,9 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
     {
         return new(Angle, Center, RealDimensions / 2, Dimensions / 2, CalculateResolution(), GuidValue, Delayed, ForceRefreshFinalImage);
     }
+
+    private void OnReferenceImageSizeChanged(object? sender, SizeChangedEventArgs e)
+    {
+        PropertyChanged?.Invoke(this, new(nameof(ReferenceLayerScale)));
+    }
 }

+ 50 - 2
src/PixiEditorPrototype/ViewModels/DocumentViewModel.cs

@@ -14,6 +14,7 @@ using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.Parser;
 using PixiEditorPrototype.CustomControls.SymmetryOverlay;
+using PixiEditorPrototype.Helpers;
 using PixiEditorPrototype.Models;
 using SkiaSharp;
 
@@ -39,6 +40,7 @@ internal class DocumentViewModel : INotifyPropertyChanged
     public RelayCommand? ToggleLockTransparencyCommand { get; }
     public RelayCommand? ApplyTransformCommand { get; }
     public RelayCommand? PasteImageCommand { get; }
+    public RelayCommand? CreateReferenceLayerCommand { get; }
     public RelayCommand? DragSymmetryCommand { get; }
     public RelayCommand? EndDragSymmetryCommand { get; }
     public RelayCommand? ClipToMemberBelowCommand { get; }
@@ -160,6 +162,22 @@ internal class DocumentViewModel : INotifyPropertyChanged
     public int ResizeWidth { get; set; } = 1024;
     public int ResizeHeight { get; set; } = 1024;
 
+    public IReadOnlyReferenceLayer? ReferenceLayer => Helpers.Tracker.Document.ReferenceLayer;
+
+    public BitmapSource? ReferenceBitmap => ReferenceLayer?.Image.ToWriteableBitmap();
+    public VecI ReferenceBitmapSize => ReferenceLayer?.Image.Size ?? VecI.Zero;
+    public ShapeCorners ReferenceShape => ReferenceLayer?.Shape ?? default;
+
+    public Matrix ReferenceTransformMatrix
+    {
+        get
+        {
+            if (ReferenceLayer is null)
+                return Matrix.Identity;
+            var skiaMatrix = OperationHelper.CreateMatrixFromPoints(ReferenceLayer.Shape, ReferenceLayer.Image.Size);
+            return new Matrix(skiaMatrix.ScaleX, skiaMatrix.SkewY, skiaMatrix.SkewX, skiaMatrix.ScaleY, skiaMatrix.TransX, skiaMatrix.TransY);
+        }
+    }
 
     private DocumentHelpers Helpers { get; }
 
@@ -180,6 +198,7 @@ internal class DocumentViewModel : INotifyPropertyChanged
     private bool drawingBrightness = false;
     private bool transformingRectangle = false;
     private bool transformingEllipse = false;
+    private bool transformingReferenceLayer = false;
     private bool shiftingLayer = false;
 
     private bool transformingSelectionPath = false;
@@ -220,6 +239,7 @@ internal class DocumentViewModel : INotifyPropertyChanged
         DeleteMaskCommand = new RelayCommand(DeleteMask);
         ToggleLockTransparencyCommand = new RelayCommand(ToggleLockTransparency);
         PasteImageCommand = new RelayCommand(PasteImage);
+        CreateReferenceLayerCommand = new RelayCommand(CreateReferenceLayer);
         ApplyTransformCommand = new RelayCommand(ApplyTransform);
         DragSymmetryCommand = new RelayCommand(DragSymmetry);
         EndDragSymmetryCommand = new RelayCommand(EndDragSymmetry);
@@ -616,7 +636,7 @@ internal class DocumentViewModel : INotifyPropertyChanged
 
     private void ApplyTransform(object? param)
     {
-        if (!transformingRectangle && !pastingImage && !transformingSelectionPath && !transformingEllipse)
+        if (!transformingRectangle && !pastingImage && !transformingSelectionPath && !transformingEllipse && !transformingReferenceLayer)
             return;
 
         if (transformingRectangle)
@@ -645,7 +665,12 @@ internal class DocumentViewModel : INotifyPropertyChanged
             TransformViewModel.HideTransform();
             Helpers.ActionAccumulator.AddFinishedActions(new EndTransformSelectionPath_Action());
         }
-
+        else if (transformingReferenceLayer)
+        {
+            transformingReferenceLayer = false;
+            TransformViewModel.HideTransform();
+            Helpers.ActionAccumulator.AddFinishedActions(new EndCreateReferenceLayer_Action());
+        }
         updateableChangeActive = false;
     }
 
@@ -709,6 +734,10 @@ internal class DocumentViewModel : INotifyPropertyChanged
         {
             Helpers.ActionAccumulator.AddActions(new TransformSelectionPath_Action(newCorners));
         }
+        else if (transformingReferenceLayer)
+        {
+            Helpers.ActionAccumulator.AddActions(new CreateReferenceLayer_Action(null, newCorners));
+        }
     }
 
     public void FloodFill(VecI pos, SKColor color, bool referenceAllLayers)
@@ -744,6 +773,25 @@ internal class DocumentViewModel : INotifyPropertyChanged
         TransformViewModel.ShowFreeTransform(corners);
     }
 
+    private void CreateReferenceLayer(object? args)
+    {
+        OpenFileDialog dialog = new();
+        if (dialog.ShowDialog() != true)
+            return;
+
+        var referenceImage = Surface.Load(dialog.FileName);
+
+        double shapeWidth;
+        double shapeHeight;
+
+        RectD referenceImageRect = new RectD(VecD.Zero, SizeBindable).AspectFit(new RectD(VecD.Zero, referenceImage.Size));
+        ShapeCorners corners = new ShapeCorners(referenceImageRect);
+
+        Helpers.ActionAccumulator.AddActions(new CreateReferenceLayer_Action(referenceImage, corners));
+        transformingReferenceLayer = true;
+        TransformViewModel.ShowShapeTransform(corners);
+    }
+
     private void ClearSelection(object? param)
     {
         if (updateableChangeActive)

+ 11 - 0
src/PixiEditorPrototype/Views/MainWindow.xaml

@@ -65,6 +65,17 @@
                         Delete
                     </Button>
                 </StackPanel>
+                <StackPanel 
+                    DockPanel.Dock="Top" 
+                    Orientation="Horizontal" 
+                    Margin="0,5,0,0">
+                    <Button 
+                        Margin="5,0" 
+                        Command="{Binding ActiveDocument.CreateReferenceLayerCommand}" 
+                        Width="80">
+                        Add reference
+                    </Button>
+                </StackPanel>
                 <StackPanel
                     DockPanel.Dock="Top"
                     Orientation="Horizontal"