From cd452ee5807009ccf3a2549ed560c7b167145472 Mon Sep 17 00:00:00 2001 From: Peter Gulyas Date: Thu, 30 Nov 2023 21:26:07 +0100 Subject: [PATCH] Fixed the undo system --- Source/Contrib/TrackViewer/SceneViewer.cs | 67 +++++++--- .../RunActivity/Viewer3D/EditorPrimitives.cs | 122 ++++++++++-------- 2 files changed, 112 insertions(+), 77 deletions(-) diff --git a/Source/Contrib/TrackViewer/SceneViewer.cs b/Source/Contrib/TrackViewer/SceneViewer.cs index 1bfe30c21b..d8fdb94e7a 100644 --- a/Source/Contrib/TrackViewer/SceneViewer.cs +++ b/Source/Contrib/TrackViewer/SceneViewer.cs @@ -58,6 +58,7 @@ public class SceneViewer OrbitingCamera Camera; Stack UndoStack = new Stack(); Stack RedoStack = new Stack(); + EditorState EditorState; /// The command-line arguments private string[] CommandLineArgs; @@ -126,19 +127,27 @@ public void Update(GameTime gameTime) { SelectedObject = selectedObject; SelectedObjectChanged(); + EditorState = EditorState.ObjectSelected; } } if (UserInput.IsPressed(UserCommand.EditorUnselectAll)) { - SelectedObject = null; - SelectedObjectChanged(); + if (EditorState == EditorState.ObjectSelected || EditorState == EditorState.Default) + { + SetDefaultMode(); + } } if (UserInput.IsPressed(UserCommand.EditorUndo)) { - UndoCommand(); + if (EditorState == EditorState.ObjectSelected || EditorState == EditorState.Default) + { + SetDefaultMode(); + UndoCommand(); + } } if (UserInput.IsPressed(UserCommand.EditorRedo)) { + SetDefaultMode(); RedoCommand(); } @@ -198,12 +207,12 @@ public async Task SetCameraLocation() mouseLocation.Location.Y = elevatedLocation + 15; Camera.SetLocation(mouseLocation); - var lastView = UndoStack.Count > 0 ? UndoStack.Last(s => s.UndoEvent == UndoEvent.ViewChanged) : + var lastView = UndoStack.Count > 0 ? UndoStack.First(s => s.UndoEvent == UndoEvent.ViewChanged) : new UndoDataSet() { - OldCameraLocation = Camera.CameraWorldLocation, - OldCameraRotationXRadians = Camera.GetRotationX(), - OldCameraRotationYRadians = Camera.GetRotationY(), + NewCameraLocation = Camera.CameraWorldLocation, + NewCameraRotationXRadians = Camera.GetRotationX(), + NewCameraRotationYRadians = Camera.GetRotationY(), }; UndoStack.Push(new UndoDataSet() @@ -222,12 +231,16 @@ void UpdateViewUndoState() { if (UndoStack.Count == 0) return; + + var lastView = UndoStack.First(s => s.UndoEvent == UndoEvent.ViewChanged); + + if (Camera.GetRotationX() == lastView.NewCameraRotationXRadians && Camera.GetRotationY() == lastView.NewCameraRotationYRadians && Camera.CameraWorldLocation == lastView.NewCameraLocation) + return; - var lastView = UndoStack.Last(s => s.UndoEvent == UndoEvent.ViewChanged); - if (lastView == UndoStack.Last()) + if (UndoStack.First().UndoEvent == UndoEvent.ViewChanged) // then updatable { - if (lastView.NewCameraLocation == lastView.OldCameraLocation && (Camera.GetRotationX() != lastView.NewCameraRotationXRadians || Camera.GetRotationY() != lastView.NewCameraRotationYRadians) - || lastView.NewCameraLocation != lastView.OldCameraLocation && Camera.CameraWorldLocation == lastView.NewCameraLocation) + if ((Camera.GetRotationX() == lastView.NewCameraRotationXRadians && Camera.GetRotationY() == lastView.NewCameraRotationYRadians) ^ + (lastView.NewCameraRotationXRadians != lastView.OldCameraRotationXRadians || lastView.NewCameraRotationYRadians != lastView.OldCameraRotationYRadians)) { // Group rotations and pan-zooms by just updating the last action lastView.NewCameraRotationXRadians = Camera.GetRotationX(); @@ -237,7 +250,7 @@ void UpdateViewUndoState() return; } } - if (Camera.GetRotationX() != lastView.NewCameraRotationXRadians || Camera.GetRotationY() != lastView.NewCameraRotationYRadians || Camera.CameraWorldLocation == lastView.NewCameraLocation) + if (Camera.GetRotationX() != lastView.NewCameraRotationXRadians || Camera.GetRotationY() != lastView.NewCameraRotationYRadians || Camera.CameraWorldLocation != lastView.NewCameraLocation) { UndoStack.Push(new UndoDataSet() { @@ -253,19 +266,21 @@ void UpdateViewUndoState() } } + void SetDefaultMode() + { + SelectedObject = null; + SelectedObjectChanged(); + EditorState = EditorState.Default; + } + void UndoCommand() { - UndoDataSet undoDataSet; if (UndoStack.Count > 1) { - undoDataSet = UndoStack.Pop(); + var undoDataSet = UndoStack.Pop(); RedoStack.Push(undoDataSet); + UndoRedo(undoDataSet, true); } - else - { - undoDataSet = UndoStack.Peek(); - } - UndoRedo(undoDataSet, true); } void RedoCommand() @@ -283,8 +298,9 @@ void UndoRedo(UndoDataSet undoDataSet, bool undo) if (undoDataSet.UndoEvent == UndoEvent.ViewChanged) { Camera.SetLocation(undo ? undoDataSet.OldCameraLocation : undoDataSet.NewCameraLocation); - Camera.RotationXTargetRadians = undo ? undoDataSet.OldCameraRotationXRadians : undoDataSet.NewCameraRotationXRadians; - Camera.RotationYTargetRadians = undo ? undoDataSet.OldCameraRotationYRadians : undoDataSet.NewCameraRotationYRadians; + Camera.SetRotation( + undo ? undoDataSet.OldCameraRotationXRadians : undoDataSet.NewCameraRotationXRadians, + undo ? undoDataSet.OldCameraRotationYRadians : undoDataSet.NewCameraRotationYRadians); } } @@ -370,6 +386,15 @@ public enum UndoEvent WorldObjectChanged, } + public enum EditorState + { + Default = 0, + ObjectSelected, + ObjectMovingX, + ObjectMovingY, + ObjectMovingZ, + } + public class SceneViewerHwndHost : HwndHost { readonly IntPtr HwndChildHandle; diff --git a/Source/RunActivity/Viewer3D/EditorPrimitives.cs b/Source/RunActivity/Viewer3D/EditorPrimitives.cs index ef75633f42..74c3b1a492 100644 --- a/Source/RunActivity/Viewer3D/EditorPrimitives.cs +++ b/Source/RunActivity/Viewer3D/EditorPrimitives.cs @@ -22,8 +22,6 @@ using ORTS.Common; using System; using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; namespace Orts.Viewer3D @@ -50,10 +48,10 @@ public class EditorShapes : StaticShape, IDisposable public EditorShapes(Viewer viewer) : base(viewer, "", null, ShapeFlags.None, null, -1) { - MouseCrosshair = new MouseCrosshair(Viewer, Color.GreenYellow); + MouseCrosshair = new MouseCrosshair(Viewer, Color.GreenYellow, Color.Red, Color.Cyan); HandleX = new HandleX(Viewer, Color.Red); HandleY = new HandleY(Viewer, Color.Blue); - HandleZ = new HandleZ(Viewer, Color.Green); + HandleZ = new HandleZ(Viewer, Color.LightGreen); } public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime) @@ -189,26 +187,54 @@ public override void Draw(GraphicsDevice graphicsDevice) } [CallOnThread("Loader")] - public class BoundingBoxPrimitive : EditorPrimitive + public class BoxPrimitive : EditorPrimitive { - static IndexBuffer BoundingBoxIndexBuffer; - public readonly Matrix ComplexTransform; + static IndexBuffer BoxIndexBuffer; - public BoundingBoxPrimitive(Viewer viewer, BoundingBox boundingBox, Color color) + public BoxPrimitive(Viewer viewer, float size, Color color) + : this(viewer, new Vector3(-size / 2), new Vector3(size / 2), color) + { + Material = viewer.MaterialManager.Load("EditorPrimitive"); + if (BoxIndexBuffer == null) + { + var indexData = new short[] { 2, 3, 6, 7, 5, 3, 1, 2, 0, 6, 4, 5, 0, 1 }; + BoxIndexBuffer = new IndexBuffer(viewer.GraphicsDevice, typeof(short), indexData.Length, BufferUsage.WriteOnly); + BoxIndexBuffer.SetData(indexData); + } + IndexBuffer = BoxIndexBuffer; + PrimitiveCount = IndexBuffer.IndexCount - 2; + PrimitiveType = PrimitiveType.TriangleStrip; + } + + protected BoxPrimitive(Viewer viewer, Vector3 min, Vector3 max, Color color) { var vertexData = new VertexPositionColor[] { - new VertexPositionColor(boundingBox.Min, color), - new VertexPositionColor(new Vector3(boundingBox.Min.X, boundingBox.Min.Y, boundingBox.Max.Z), color), - new VertexPositionColor(new Vector3(boundingBox.Min.X, boundingBox.Max.Y, boundingBox.Min.Z), color), - new VertexPositionColor(new Vector3(boundingBox.Min.X, boundingBox.Max.Y, boundingBox.Max.Z), color), - new VertexPositionColor(new Vector3(boundingBox.Max.X, boundingBox.Min.Y, boundingBox.Min.Z), color), - new VertexPositionColor(new Vector3(boundingBox.Max.X, boundingBox.Min.Y, boundingBox.Max.Z), color), - new VertexPositionColor(new Vector3(boundingBox.Max.X, boundingBox.Max.Y, boundingBox.Min.Z), color), - new VertexPositionColor(boundingBox.Max, color) + new VertexPositionColor(min, color), + new VertexPositionColor(new Vector3(min.X, min.Y, max.Z), color), + new VertexPositionColor(new Vector3(min.X, max.Y, min.Z), color), + new VertexPositionColor(new Vector3(min.X, max.Y, max.Z), color), + new VertexPositionColor(new Vector3(max.X, min.Y, min.Z), color), + new VertexPositionColor(new Vector3(max.X, min.Y, max.Z), color), + new VertexPositionColor(new Vector3(max.X, max.Y, min.Z), color), + new VertexPositionColor(max, color) }; VertexBuffer = new VertexBuffer(viewer.GraphicsDevice, typeof(VertexPositionColor), vertexData.Length, BufferUsage.WriteOnly); VertexBuffer.SetData(vertexData); + } + } + + [CallOnThread("Loader")] + public class BoundingBoxPrimitive : BoxPrimitive + { + static IndexBuffer BoundingBoxIndexBuffer; + public readonly Matrix ComplexTransform; + + public BoundingBoxPrimitive(Viewer viewer, BoundingBox boundingBox, Color color) + : base(viewer, boundingBox.Min, boundingBox.Max, color) + { + Material = viewer.MaterialManager.Load("EditorPrimitive"); + ComplexTransform = boundingBox.ComplexTransform; if (BoundingBoxIndexBuffer == null) { var indexData = new short[] { 0, 1, 0, 2, 0, 4, 1, 3, 1, 5, 2, 3, 2, 6, 3, 7, 4, 5, 4, 6, 5, 7, 6, 7 }; @@ -218,23 +244,21 @@ public BoundingBoxPrimitive(Viewer viewer, BoundingBox boundingBox, Color color) IndexBuffer = BoundingBoxIndexBuffer; PrimitiveCount = IndexBuffer.IndexCount / 2; PrimitiveType = PrimitiveType.LineList; - Material = viewer.MaterialManager.Load("EditorPrimitive"); - ComplexTransform = boundingBox.ComplexTransform; } } [CallOnThread("Loader")] public class MouseCrosshair : EditorPrimitive { - public MouseCrosshair(Viewer viewer, Color color) + public MouseCrosshair(Viewer viewer, Color color, Color northColor, Color southColor) { var vertexData = new VertexPositionColor[] { new VertexPositionColor(new Vector3(-5, 0, 0), color), new VertexPositionColor(new Vector3(5, 0, 0), color), - new VertexPositionColor(new Vector3(0, 0, -5), Color.Red), - new VertexPositionColor(new Vector3(0, 0, 5), Color.Cyan), - new VertexPositionColor(new Vector3(0, 0, 0), color), + new VertexPositionColor(new Vector3(0, 0, -5), northColor), + new VertexPositionColor(new Vector3(0, 0, 5), southColor), + new VertexPositionColor(new Vector3(0, -5, 0), color), new VertexPositionColor(new Vector3(0, 20, 0), color) }; VertexBuffer = new VertexBuffer(viewer.GraphicsDevice, typeof(VertexPositionColor), vertexData.Length, BufferUsage.WriteOnly); @@ -253,54 +277,40 @@ public HandleX(Viewer viewer, Color color) var vertexData = GetVertexData(color); VertexBuffer = new VertexBuffer(viewer.GraphicsDevice, typeof(VertexPositionColor), vertexData.Length, BufferUsage.WriteOnly); VertexBuffer.SetData(vertexData); - PrimitiveCount = VertexBuffer.VertexCount / 2; - PrimitiveType = PrimitiveType.TriangleList; + PrimitiveCount = VertexBuffer.VertexCount - 2; + PrimitiveType = PrimitiveType.TriangleStrip; Material = viewer.MaterialManager.Load("EditorPrimitive"); } protected virtual VertexPositionColor[] GetVertexData(Color color) => GetVertexData(0, 1, 2, color); protected VertexPositionColor[] GetVertexData(int x, int y, int z, Color color) { - var l = 5f; - var d = 0.1f; - var a = l / 5; - var b = a / 4; + var l = 5f; // total length, meter + var d = 0.1f; // shaft half thickness + var a = l / 5; // arrow head length + var b = a / 4; // arrow head half thickness var c = l - a; var data = new float[][] { - new[] { 0, +d, 0 }, - new[] { c, +d, 0 }, - new[] { 0, -d, 0 }, + // Arrow shaft + new[] { 0, d, 0 }, + new[] { c, d, 0 }, + new[] { 0, 0, d }, + new[] { c, 0, d }, new[] { 0, -d, 0 }, - new[] { c, +d, 0 }, new[] { c, -d, 0 }, - - new[] { 0, 0, +d }, - new[] { c, 0, +d }, - new[] { 0, 0, -d }, new[] { 0, 0, -d }, - new[] { c, 0, +d }, new[] { c, 0, -d }, - new[] { l, 0, 0 }, - new[] { l - a, +b, +b }, - new[] { l - a, -b, +b }, - new[] { l, 0, 0 }, - new[] { l - a, -b, +b }, - new[] { l - a, -b, -b }, - new[] { l, 0, 0 }, - new[] { l - a, -b, -b }, - new[] { l - a, +b, -b }, - new[] { l, 0, 0 }, - new[] { l - a, +b, -b }, - new[] { l - a, +b, +b }, - - new[] { l - a, +b, +b }, - new[] { l - a, +b, -b }, - new[] { l - a, -b, -b }, - new[] { l - a, -b, -b }, - new[] { l - a, +b, -b }, - new[] { l - a, -b, +b }, + // Arrow head + new[] { l, 0, 0 }, + new[] { c, +b, +b }, + new[] { c, -b, +b }, + new[] { c, -b, -b }, + new[] { l, 0, 0 }, + new[] { c, +b, -b }, + new[] { c, +b, +b }, + new[] { c, -b, -b }, }; var vertexData = new VertexPositionColor[data.Length]; for (var i = 0; i < data.Length; i++)