From a3221d437bc6f290f3c3adf441f4074410ee3747 Mon Sep 17 00:00:00 2001 From: Peter Gulyas Date: Sat, 9 Dec 2023 18:59:33 +0100 Subject: [PATCH 1/2] Construction lines at object move --- .../TrackViewer/UserInterface/SceneView.xaml | 34 ++-- .../UserInterface/SceneView.xaml.cs | 155 +++++++++++++----- .../RunActivity/Viewer3D/EditorPrimitives.cs | 135 ++++++++++++++- 3 files changed, 263 insertions(+), 61 deletions(-) diff --git a/Source/Contrib/TrackViewer/UserInterface/SceneView.xaml b/Source/Contrib/TrackViewer/UserInterface/SceneView.xaml index f32801cffc..2b987b03cc 100644 --- a/Source/Contrib/TrackViewer/UserInterface/SceneView.xaml +++ b/Source/Contrib/TrackViewer/UserInterface/SceneView.xaml @@ -10,15 +10,21 @@ - - - + + + + + + - - - - + + + + + + + @@ -26,12 +32,16 @@ - - + + - - - + + + + + + + diff --git a/Source/Contrib/TrackViewer/UserInterface/SceneView.xaml.cs b/Source/Contrib/TrackViewer/UserInterface/SceneView.xaml.cs index 69a89d4f9d..25ff054c88 100644 --- a/Source/Contrib/TrackViewer/UserInterface/SceneView.xaml.cs +++ b/Source/Contrib/TrackViewer/UserInterface/SceneView.xaml.cs @@ -33,6 +33,7 @@ public partial class SceneView : Window EditorState EditorState; EditorMoveState EditorMoveState; StaticShape SelectedObject; + StaticShape SnappedObject; WorldFile SelectedWorldFile; Orts.Formats.Msts.WorldObject SelectedWorldObject; StaticShape MovedObject; @@ -40,10 +41,24 @@ public partial class SceneView : Window WorldPosition HandlePosition; WorldPosition HandleOriginalPosition; float DeltaX, DeltaY, DeltaZ; + Vector3 ConstructionX, ConstructionY, ConstructionZ; + float ConstructionAngle; UndoDataSet DeltaContext; WorldLocation CursorLocation; readonly List<(int TileX, int TileZ)> FlaggedTiles = new List<(int, int)>(); + bool OrthoMode { get; set; } + bool ElevationLock { get; set; } + bool ObjectSnap { get; set; } + + // Editing commands + public static RoutedCommand Rotate = new RoutedCommand(); + public static RoutedCommand Move = new RoutedCommand(); + public static RoutedCommand MoveHandle = new RoutedCommand(); + public static RoutedCommand ToggleOrtho = new RoutedCommand(); + public static RoutedCommand ToggleElevationLock = new RoutedCommand(); + public static RoutedCommand ToggleObjectSnap = new RoutedCommand(); + public SceneView(IntPtr hostWindow) { InitializeComponent(); @@ -64,31 +79,21 @@ public void Update(GameTime gameTime) { ApplicationCommands.Stop.Execute(null, null); } - - if (EditorState == EditorState.Default || EditorState == EditorState.ObjectSelected) - { - if (UserInput.IsMouseLeftButtonPressed && UserInput.ModifiersMaskShiftCtrlAlt(false, false, false)) - { - if (Camera.PickByMouse(out var selectedObject)) - { - SelectedObject = selectedObject; - SelectedObjectChanged(); - EditorState = EditorState.ObjectSelected; - } - } - } - if (EditorState == EditorState.HandleMoving) - { - if (UserInput.IsMouseLeftButtonPressed) - { - ApplyHandleMove(); - } - } - if (EditorState == EditorState.ObjectMoving) + if (UserInput.IsMouseLeftButtonPressed) { - if (UserInput.IsMouseLeftButtonPressed) + switch (EditorState) { - ApplyObjectMove(); + case EditorState.Default: + case EditorState.ObjectSelected: + if (UserInput.ModifiersMaskShiftCtrlAlt(false, false, false) && Camera.PickByMouse(out var selectedObject)) + { + SelectedObject = selectedObject; + SelectedObjectChanged(); + EditorState = EditorState.ObjectSelected; + } + break; + case EditorState.HandleMoving: ApplyHandleMove(); break; + case EditorState.ObjectMoving: ApplyObjectMove(); break; } } @@ -102,9 +107,27 @@ public void Update(GameTime gameTime) // A second pass after user input handled, do the effective work if (EditorState == EditorState.ObjectMoving) { + if (ObjectSnap && Camera.PickByMouse(out var snappedObject)) + { + SnappedObject = snappedObject; + Viewer.EditorShapes.BoundingBoxShapes.Add(SnappedObject); + } + else + { + SnappedObject = null; + Viewer.EditorShapes.BoundingBoxShapes.TryTake(out _); + } MovedObject.Location.XNAMatrix = GetMovingMatrix(MovedObjectOriginalPosition, HandleOriginalPosition, HandlePosition); Viewer.EditorShapes.MovedObject = MovedObject; Viewer.EditorShapes.MovedObjectLocation = MovedObject.Location; + Viewer.EditorShapes.HandleLocation = HandlePosition; + Viewer.EditorShapes.ConstructionOriginalTranslation = (HandleOriginalPosition ?? MovedObjectOriginalPosition).XNAMatrix.Translation; + Viewer.EditorShapes.ConstructionLinesEnabled = true; + Viewer.EditorShapes.ConsturcionLineAngleStyle = EditorMoveState == EditorMoveState.Rotate; + Viewer.EditorShapes.ConstructionLineX = ConstructionX; + Viewer.EditorShapes.ConstructionLineY = ConstructionY; + Viewer.EditorShapes.ConstructionLineZ = ConstructionZ; + Viewer.EditorShapes.ConstructionAngle = ConstructionAngle; } else { @@ -116,6 +139,18 @@ public void Update(GameTime gameTime) { HandlePosition.XNAMatrix = GetMovingMatrix(HandleOriginalPosition); Viewer.EditorShapes.HandleLocation = HandlePosition; + Viewer.EditorShapes.ConstructionOriginalTranslation = HandleOriginalPosition.XNAMatrix.Translation; + Viewer.EditorShapes.ConstructionLinesEnabled = true; + Viewer.EditorShapes.ConsturcionLineAngleStyle = EditorMoveState == EditorMoveState.Rotate; + Viewer.EditorShapes.ConstructionLineX = ConstructionX; + Viewer.EditorShapes.ConstructionLineY = ConstructionY; + Viewer.EditorShapes.ConstructionLineZ = ConstructionZ; + Viewer.EditorShapes.ConstructionAngle = ConstructionAngle; + } + + if (EditorState != EditorState.ObjectMoving && EditorState != EditorState.HandleMoving) + { + Viewer.EditorShapes.ConstructionLinesEnabled = false; } FillDeltaStatus(); @@ -198,24 +233,47 @@ public async Task SetCameraLocation(WorldLocation worldLocation) Matrix GetMovingMatrix(in WorldPosition originalPosition, in WorldPosition handleOriginalPosition = null, WorldPosition handlePosition = null) { - var handle = handleOriginalPosition ?? originalPosition; + var handle = handlePosition ?? originalPosition; var xnaMatrix = originalPosition.XNAMatrix; if (EditorMoveState == EditorMoveState.Rotate) { - var distance = WorldLocation.GetDistance(handle.WorldLocation, CursorLocation); - distance.Z *= -1; + float constructionRadius; + double targetAngle; + if (ObjectSnap && SnappedObject != null) + { + var distance = WorldLocation.GetDistance(handle.WorldLocation, SnappedObject.Location.WorldLocation); + distance.Z *= -1; + distance.Y = 0; + constructionRadius = distance.Length(); + targetAngle = Math.Atan2(SnappedObject.Location.XNAMatrix.M13, SnappedObject.Location.XNAMatrix.M33); + } + else + { + var distance = WorldLocation.GetDistance(handle.WorldLocation, CursorLocation); + distance.Z *= -1; + distance.Y = 0; + constructionRadius = distance.Length(); + targetAngle = Math.Atan2(distance.Z, distance.X); + } - var angle = MathHelper.WrapAngle((float)(Math.Atan2(originalPosition.XNAMatrix.M13, originalPosition.XNAMatrix.M33) - Math.Atan2(distance.Z, distance.X))); + var angle = MathHelper.WrapAngle((float)(Math.Atan2(originalPosition.XNAMatrix.M13, originalPosition.XNAMatrix.M33) - targetAngle)); var rotation = Matrix.CreateFromYawPitchRoll(angle, 0, 0); var translation = handle.XNAMatrix.Translation; xnaMatrix.Translation -= translation; xnaMatrix *= rotation; xnaMatrix.Translation += translation; + DeltaX = 0; + DeltaY = MathHelper.ToDegrees(angle); + DeltaZ = 0; + ConstructionAngle = angle; + ConstructionX = constructionRadius * Vector3.UnitX; + ConstructionZ = constructionRadius * Vector3.Transform(Vector3.UnitX, Matrix.CreateFromYawPitchRoll(-angle, 0, 0)); + if (handlePosition != null && handleOriginalPosition != null) { - angle = MathHelper.WrapAngle((float)(Math.Atan2(handleOriginalPosition.XNAMatrix.M13, handleOriginalPosition.XNAMatrix.M33) - Math.Atan2(distance.Z, distance.X))); + angle = MathHelper.WrapAngle((float)(Math.Atan2(handleOriginalPosition.XNAMatrix.M13, handleOriginalPosition.XNAMatrix.M33) - targetAngle)); rotation = Matrix.CreateFromYawPitchRoll(angle, 0, 0); var handleMatrix = handleOriginalPosition.XNAMatrix; handleMatrix.Translation -= translation; @@ -223,14 +281,11 @@ Matrix GetMovingMatrix(in WorldPosition originalPosition, in WorldPosition handl handleMatrix.Translation += translation; handlePosition.XNAMatrix = handleMatrix; } - - DeltaX = 0; - DeltaY = MathHelper.ToDegrees(angle); - DeltaZ = 0; } else if (EditorMoveState == EditorMoveState.Move) { - var distance = WorldLocation.GetDistance(originalPosition.WorldLocation, CursorLocation); + var targetLocation = ObjectSnap && SnappedObject != null ? SnappedObject.Location.WorldLocation : CursorLocation; + var distance = WorldLocation.GetDistance(originalPosition.WorldLocation, targetLocation); distance.Z *= -1; var axisX = Vector3.Normalize(handle.XNAMatrix.Right); @@ -239,7 +294,7 @@ Matrix GetMovingMatrix(in WorldPosition originalPosition, in WorldPosition handl var tileLocation = xnaMatrix.Translation; - if (UserInput.IsDown(UserCommand.EditorLockOrthogonal)) + if (OrthoMode) { var distanceX = Vector3.Dot(axisX, distance); var distanceZ = Vector3.Dot(axisZ, distance); @@ -252,7 +307,7 @@ Matrix GetMovingMatrix(in WorldPosition originalPosition, in WorldPosition handl tileLocation.Z += distance.Z; } - if (!UserInput.IsDown(UserCommand.EditorLockElevation)) + if (!ElevationLock) { tileLocation.Y = Viewer.Tiles.GetElevation(handle.TileX, handle.TileZ, tileLocation.X, -tileLocation.Z); } @@ -270,6 +325,9 @@ Matrix GetMovingMatrix(in WorldPosition originalPosition, in WorldPosition handl DeltaX = Vector3.Dot(axisX, distance); DeltaY = Vector3.Dot(axisY, distance); DeltaZ = Vector3.Dot(axisZ, distance); + ConstructionX = DeltaX * Vector3.UnitX; + ConstructionY = DeltaY * Vector3.UnitY; + ConstructionZ = DeltaZ * Vector3.UnitZ; } return xnaMatrix; } @@ -376,6 +434,10 @@ void CancelObjectMove() { MovedObject.Location.CopyFrom(MovedObjectOriginalPosition); MovedObject = null; + if (HandleOriginalPosition != null) + HandlePosition.CopyFrom(HandleOriginalPosition); + else + HandlePosition = null; EditorState = EditorState.ObjectSelected; } @@ -424,8 +486,11 @@ void SelectedObjectChanged() Viewer.EditorShapes.SelectedObject = SelectedObject; Viewer.EditorShapes.MovedObject = null; Viewer.EditorShapes.HandleLocation = null; + while (!Viewer.EditorShapes.BoundingBoxShapes.IsEmpty) + Viewer.EditorShapes.BoundingBoxShapes.TryTake(out _); HandlePosition = null; HandleOriginalPosition = null; + SnappedObject = null; SelectedWorldFile = Viewer.World.Scenery.WorldFiles.SingleOrDefault(w => w.TileX == SelectedObject?.Location.TileX && w.TileZ == SelectedObject?.Location.TileZ); SelectedWorldObject = SelectedWorldFile?.MstsWFile?.Tr_Worldfile?.SingleOrDefault(o => o.UID == SelectedObject?.Uid); @@ -477,11 +542,6 @@ protected override void OnClosing(CancelEventArgs e) Hide(); } - private void IntValidationTextBox(object sender, TextCompositionEventArgs e) - { - e.Handled = int.TryParse(e.Text, out var _); - } - private void UndoRedoCanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = EditorState == EditorState.Default || EditorState == EditorState.ObjectSelected; @@ -500,25 +560,34 @@ private void CancelCommand(object sender, ExecutedRoutedEventArgs e) private void RotateCommand(object sender, ExecutedRoutedEventArgs e) { EditorMoveState = EditorMoveState.Rotate; - if (EditorState == EditorState.ObjectSelected) StartObjectMove(); + Keyboard.Focus(DeltaYBlock); } private void MoveCommand(object sender, ExecutedRoutedEventArgs e) { EditorMoveState = EditorMoveState.Move; - if (EditorState == EditorState.ObjectSelected) StartObjectMove(); + Keyboard.Focus(DeltaXBlock); } private void MoveHandleCommand(object sender, ExecutedRoutedEventArgs e) { EditorMoveState = EditorMoveState.Move; - if (EditorState == EditorState.ObjectSelected) StartHandleMove(); + Keyboard.Focus(DeltaXBlock); + } + + private void ToggleOrthoCommand(object sender, ExecutedRoutedEventArgs e) => OrthoMode = !OrthoMode; + private void ToggleElevationLockCommand(object sender, ExecutedRoutedEventArgs e) => ElevationLock = !ElevationLock; + private void ToggleObjectSnapCommand(object sender, ExecutedRoutedEventArgs e) => ObjectSnap = !ObjectSnap; + + private void IntValidationTextBox(object sender, TextCompositionEventArgs e) + { + e.Handled = int.TryParse(e.Text, out var _); } private void UintValidationTextBox(object sender, TextCompositionEventArgs e) diff --git a/Source/RunActivity/Viewer3D/EditorPrimitives.cs b/Source/RunActivity/Viewer3D/EditorPrimitives.cs index 2be44d44b1..64d55ae524 100644 --- a/Source/RunActivity/Viewer3D/EditorPrimitives.cs +++ b/Source/RunActivity/Viewer3D/EditorPrimitives.cs @@ -32,6 +32,7 @@ public class EditorShapes : StaticShape, IDisposable readonly MouseCrosshair MouseCrosshair; public bool MouseCrosshairEnabled { get; set; } public bool CrosshairPositionUpdateEnabled { get; set; } = true; + Vector3 CrosshairPosition; readonly HandleX HandleX; readonly HandleY HandleY; @@ -50,14 +51,38 @@ public class EditorShapes : StaticShape, IDisposable public ConcurrentBag BoundingBoxShapes = new ConcurrentBag(); readonly ConcurrentDictionary<(int tileX, int tileZ, int uid, Matrix matrix, int number), BoundingBoxPrimitive> BoundingBoxPrimitives = new ConcurrentDictionary<(int, int, int, Matrix, int), BoundingBoxPrimitive>(); readonly ConcurrentBag UnusedPrimitives = new ConcurrentBag(); - Vector3 CrosshairPosition; + + public bool ConstructionLinesEnabled { get; set; } + public bool ConsturcionLineAngleStyle { get; set; } + public Vector3 ConstructionLineX { get; set; } + public Vector3 ConstructionLineY { get; set; } + public Vector3 ConstructionLineZ { get; set; } + public float ConstructionAngle { get; set; } + public Vector3 ConstructionOriginalTranslation { get; set; } + readonly ConstructionLine LineX; + readonly ConstructionLine LineY; + readonly ConstructionLine LineZ; + readonly ConstructionLine LineDiagonal; + readonly ConstructionArc AngleArc; + + Color XColor = Color.Red; + Color YColor = Color.Blue; + Color ZColor = Color.LightGreen; + Color DColor = Color.GreenYellow; + Color NColor = Color.Red; + Color SColor = Color.Cyan; public EditorShapes(Viewer viewer) : base(viewer, "", null, ShapeFlags.None, null, -1) { - 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.LightGreen); + MouseCrosshair = new MouseCrosshair(Viewer, DColor, NColor, SColor); + HandleX = new HandleX(Viewer, XColor); + HandleY = new HandleY(Viewer, YColor); + HandleZ = new HandleZ(Viewer, ZColor); + LineX = new ConstructionLine(Viewer, XColor); + LineY = new ConstructionLine(Viewer, YColor); + LineZ = new ConstructionLine(Viewer, ZColor); + LineDiagonal = new ConstructionLine(Viewer, DColor); + AngleArc = new ConstructionArc(Viewer, DColor); } public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime) @@ -135,12 +160,43 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime) var mouseCrosshairMatrix = Matrix.CreateTranslation(CrosshairPosition); frame.AddPrimitive(MouseCrosshair.Material, MouseCrosshair, RenderPrimitiveGroup.World, ref mouseCrosshairMatrix); } - if (HandleEnabled && (HandleLocation ?? SelectedObject?.Location) is WorldPosition handleLocation) + + var handleLocation = HandleLocation ?? SelectedObject?.Location; + if (HandleEnabled && handleLocation != null) { FrameAddPrimitive(frame, Matrix.Identity, handleLocation, HandleX); FrameAddPrimitive(frame, Matrix.Identity, handleLocation, HandleY); FrameAddPrimitive(frame, Matrix.Identity, handleLocation, HandleZ); } + if (ConstructionLinesEnabled && handleLocation != null) + { + var transform = handleLocation.XNAMatrix; + transform.Translation = ConstructionOriginalTranslation; + + if (ConsturcionLineAngleStyle) + { + LineX.Update(Vector3.Zero, ConstructionLineX); + LineDiagonal.Update(Vector3.Zero, ConstructionLineZ); + AngleArc.Update(ConstructionAngle, ConstructionLineZ.Length()); + FrameAddPrimitive(frame, Matrix.Identity, transform, handleLocation.TileX, handleLocation.TileZ, LineX); + FrameAddPrimitive(frame, Matrix.Identity, transform, handleLocation.TileX, handleLocation.TileZ, LineDiagonal); + FrameAddPrimitive(frame, Matrix.Identity, transform, handleLocation.TileX, handleLocation.TileZ, AngleArc); + } + else + { + var constructionLineXY = ConstructionLineX + ConstructionLineY; + var constructionLineXYZ = constructionLineXY + ConstructionLineZ; + LineY.Update(Vector3.Zero, ConstructionLineY); + LineX.Update(ConstructionLineY, constructionLineXY); + LineZ.Update(constructionLineXY, constructionLineXYZ); + LineDiagonal.Update(constructionLineXYZ, Vector3.Zero); + + FrameAddPrimitive(frame, Matrix.Identity, transform, handleLocation.TileX, handleLocation.TileZ, LineX); + FrameAddPrimitive(frame, Matrix.Identity, transform, handleLocation.TileX, handleLocation.TileZ, LineY); + FrameAddPrimitive(frame, Matrix.Identity, transform, handleLocation.TileX, handleLocation.TileZ, LineZ); + FrameAddPrimitive(frame, Matrix.Identity, transform, handleLocation.TileX, handleLocation.TileZ, LineDiagonal); + } + } } void FrameAddPrimitive(RenderFrame frame, Matrix localTransform, in WorldPosition worldPosition, EditorPrimitive primitive) @@ -177,6 +233,9 @@ public void Dispose() selectedObject.Value.Dispose(); } } + HandleX?.Dispose(); + HandleY?.Dispose(); + HandleZ?.Dispose(); } } @@ -288,6 +347,70 @@ public MouseCrosshair(Viewer viewer, Color color, Color northColor, Color southC } } + [CallOnThread("Loader")] + public class ConstructionLine : EditorPrimitive + { + Color Color; + + public ConstructionLine(Viewer viewer, Color color) + { + Color = color; + var vertexData = new VertexPositionColor[] + { + new VertexPositionColor(new Vector3(5, 0, 0), color), + new VertexPositionColor(new Vector3(0, 0, 0), color), + }; + VertexBuffer = new DynamicVertexBuffer(viewer.GraphicsDevice, typeof(VertexPositionColor), vertexData.Length, BufferUsage.WriteOnly); + VertexBuffer.SetData(vertexData); + PrimitiveCount = VertexBuffer.VertexCount / 2; + PrimitiveType = PrimitiveType.LineList; + Material = viewer.MaterialManager.Load("EditorPrimitive"); + } + + [CallOnThread("Render")] + public void Update(Vector3 startPosition, Vector3 endPosition) + { + var vertexData = new[] + { + new VertexPositionColor(startPosition, Color), + new VertexPositionColor(endPosition, Color) + }; + (VertexBuffer as DynamicVertexBuffer).SetData(vertexData, 0, vertexData.Length); + } + } + + [CallOnThread("Loader")] + public class ConstructionArc : EditorPrimitive + { + Color Color; + + public ConstructionArc(Viewer viewer, Color color) + { + PrimitiveCount = 50; + + Color = color; + VertexBuffer = new DynamicVertexBuffer(viewer.GraphicsDevice, typeof(VertexPositionColor), PrimitiveCount + 1, BufferUsage.WriteOnly); + PrimitiveType = PrimitiveType.LineStrip; + Material = viewer.MaterialManager.Load("EditorPrimitive"); + } + + [CallOnThread("Render")] + public void Update(float angle, float radius) + { + var vertexData = new VertexPositionColor[PrimitiveCount + 1]; + var stepAngle = angle / PrimitiveCount; + for (var i = 0; i <= PrimitiveCount; i++) + { + var iAngle = stepAngle * i; + var pos = Vector3.Zero; + pos.X = (float)(radius * Math.Cos(iAngle)); + pos.Z = (float)(radius * Math.Sin(iAngle)); + vertexData[i] = new VertexPositionColor(pos, Color); + } + (VertexBuffer as DynamicVertexBuffer).SetData(vertexData, 0, vertexData.Length); + } + } + [CallOnThread("Loader")] public class HandleX : EditorPrimitive { From 1b88d7a75d0634fdad1d0a685281721199f9140f Mon Sep 17 00:00:00 2001 From: Peter Gulyas Date: Sat, 9 Dec 2023 19:50:45 +0100 Subject: [PATCH 2/2] Object snap --- .../TrackViewer/UserInterface/SceneView.xaml.cs | 14 ++++++++++---- Source/RunActivity/Viewer3D/EditorPrimitives.cs | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Source/Contrib/TrackViewer/UserInterface/SceneView.xaml.cs b/Source/Contrib/TrackViewer/UserInterface/SceneView.xaml.cs index 25ff054c88..31ae872264 100644 --- a/Source/Contrib/TrackViewer/UserInterface/SceneView.xaml.cs +++ b/Source/Contrib/TrackViewer/UserInterface/SceneView.xaml.cs @@ -109,13 +109,16 @@ public void Update(GameTime gameTime) { if (ObjectSnap && Camera.PickByMouse(out var snappedObject)) { + if (snappedObject != SnappedObject) + Viewer.EditorShapes.BoundingBoxShapes.RemoveAll(s => s == SnappedObject); SnappedObject = snappedObject; - Viewer.EditorShapes.BoundingBoxShapes.Add(SnappedObject); + if (!Viewer.EditorShapes.BoundingBoxShapes.Contains(SnappedObject)) + Viewer.EditorShapes.BoundingBoxShapes.Add(SnappedObject); } else { + Viewer.EditorShapes.BoundingBoxShapes.RemoveAll(s => s == SnappedObject); SnappedObject = null; - Viewer.EditorShapes.BoundingBoxShapes.TryTake(out _); } MovedObject.Location.XNAMatrix = GetMovingMatrix(MovedObjectOriginalPosition, HandleOriginalPosition, HandlePosition); Viewer.EditorShapes.MovedObject = MovedObject; @@ -438,6 +441,7 @@ void CancelObjectMove() HandlePosition.CopyFrom(HandleOriginalPosition); else HandlePosition = null; + Viewer.EditorShapes.BoundingBoxShapes.Clear(); EditorState = EditorState.ObjectSelected; } @@ -457,6 +461,7 @@ void ApplyObjectMove() DeltaContext = UndoStack.Peek(); MovedObject = null; + Viewer.EditorShapes.BoundingBoxShapes.Clear(); EditorState = EditorState.ObjectSelected; } @@ -472,12 +477,14 @@ void CancelHandleMove() { HandlePosition = null; HandleOriginalPosition = null; + Viewer.EditorShapes.BoundingBoxShapes.Clear(); EditorState = EditorState.ObjectSelected; } void ApplyHandleMove() { HandleOriginalPosition = new WorldPosition(HandlePosition); + Viewer.EditorShapes.BoundingBoxShapes.Clear(); EditorState = EditorState.ObjectSelected; } @@ -486,8 +493,7 @@ void SelectedObjectChanged() Viewer.EditorShapes.SelectedObject = SelectedObject; Viewer.EditorShapes.MovedObject = null; Viewer.EditorShapes.HandleLocation = null; - while (!Viewer.EditorShapes.BoundingBoxShapes.IsEmpty) - Viewer.EditorShapes.BoundingBoxShapes.TryTake(out _); + Viewer.EditorShapes.BoundingBoxShapes.Clear(); HandlePosition = null; HandleOriginalPosition = null; SnappedObject = null; diff --git a/Source/RunActivity/Viewer3D/EditorPrimitives.cs b/Source/RunActivity/Viewer3D/EditorPrimitives.cs index 64d55ae524..3ffc48749d 100644 --- a/Source/RunActivity/Viewer3D/EditorPrimitives.cs +++ b/Source/RunActivity/Viewer3D/EditorPrimitives.cs @@ -48,7 +48,7 @@ public class EditorShapes : StaticShape, IDisposable public WorldPosition MovedObjectLocation { get; set; } BoundingBoxPrimitive MovedObjectPrimitive; - public ConcurrentBag BoundingBoxShapes = new ConcurrentBag(); + public readonly List BoundingBoxShapes = new List(); readonly ConcurrentDictionary<(int tileX, int tileZ, int uid, Matrix matrix, int number), BoundingBoxPrimitive> BoundingBoxPrimitives = new ConcurrentDictionary<(int, int, int, Matrix, int), BoundingBoxPrimitive>(); readonly ConcurrentBag UnusedPrimitives = new ConcurrentBag();