Skip to content

Commit 73db6a4

Browse files
committed
Object movement changes
1 parent b1878ca commit 73db6a4

File tree

6 files changed

+229
-82
lines changed

6 files changed

+229
-82
lines changed

Source/Contrib/TrackViewer/SceneViewer.cs

Lines changed: 154 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
using Orts.Viewer3D;
3737
using Orts.Viewer3D.Processes;
3838
using ORTS.Common.Input;
39+
using System.Windows.Media.Imaging;
3940

4041
namespace ORTS.TrackViewer
4142
{
@@ -58,7 +59,9 @@ public class SceneViewer
5859
StaticShape MovedObject;
5960
WorldPosition MovedObjectOriginalPosition;
6061
WorldPosition HandlePosition;
61-
int MoveAxis; // 0 - x, 1 - y, 2 - z
62+
WorldPosition HandleOriginalPosition;
63+
float DeltaX, DeltaY, DeltaZ;
64+
UndoDataSet DeltaContext;
6265
WorldLocation CursorLocation;
6366

6467
public SceneViewer(TrackViewer trackViewer, string[] args)
@@ -120,10 +123,10 @@ public void Update(GameTime gameTime)
120123

121124
Viewer.EditorShapes.MouseCrosshairEnabled = true;
122125

126+
UpdateViewUndoState();
127+
123128
if (EditorState == EditorState.Default || EditorState == EditorState.ObjectSelected)
124129
{
125-
UpdateViewUndoState();
126-
127130
if (UserInput.IsMouseLeftButtonPressed && UserInput.ModifiersMaskShiftCtrlAlt(false, false, false))
128131
{
129132
if (Camera.PickByMouse(out var selectedObject))
@@ -156,7 +159,7 @@ public void Update(GameTime gameTime)
156159
}
157160
if (UserInput.IsPressed(UserCommand.EditorMoveHandle))
158161
{
159-
EditorState = EditorState.HandleMoving;
162+
StartHandleMove();
160163
}
161164
}
162165
if (EditorState == EditorState.HandleMoving)
@@ -170,7 +173,7 @@ public void Update(GameTime gameTime)
170173
{
171174
CancelHandleMove();
172175
}
173-
if (UserInput.IsMouseLeftButtonPressed && UserInput.ModifiersMaskShiftCtrlAlt(false, false, false))
176+
if (UserInput.IsMouseLeftButtonPressed)
174177
{
175178
ApplyHandleMove();
176179
}
@@ -186,29 +189,39 @@ public void Update(GameTime gameTime)
186189
{
187190
CancelObjectMove();
188191
}
189-
if (UserInput.IsMouseLeftButtonPressed && UserInput.ModifiersMaskShiftCtrlAlt(false, false, false))
192+
if (UserInput.IsMouseLeftButtonPressed)
190193
{
191194
ApplyObjectMove();
192195
}
193196
}
194197

195198
CursorLocation = Camera?.CameraWorldLocation ?? new WorldLocation();
196199
CursorLocation.Location = Viewer?.TerrainPoint ?? new Vector3();
200+
CursorLocation.Location.Z *= -1;
197201
CursorLocation.Normalize();
198202
FillCursorPositionStatus(CursorLocation);
199203
SetCameraLocationStatus(Camera?.CameraWorldLocation ?? new WorldLocation());
200204

201205
// A second pass after user input handled, do the effective work
202206
if (EditorState == EditorState.ObjectMoving)
203207
{
204-
var distance = WorldLocation.GetDistance(SelectedObject.Location.WorldLocation, CursorLocation);
205-
var tileLocation = MovedObject.Location.XNAMatrix.Translation;
206-
tileLocation.X += distance.X;
207-
MovedObject.Location.XNAMatrix.Translation = tileLocation;
208-
208+
MovedObject.Location.XNAMatrix = GetMovingMatrix(MovedObjectOriginalPosition, HandleOriginalPosition, HandlePosition);
209209
Viewer.EditorShapes.MovedObject = MovedObject;
210210
Viewer.EditorShapes.MovedObjectLocation = MovedObject.Location;
211211
}
212+
else
213+
{
214+
Viewer.EditorShapes.MovedObject = null;
215+
Viewer.EditorShapes.MovedObjectLocation = null;
216+
}
217+
218+
if (EditorState == EditorState.HandleMoving)
219+
{
220+
HandlePosition.XNAMatrix = GetMovingMatrix(HandleOriginalPosition);
221+
Viewer.EditorShapes.HandleLocation = HandlePosition;
222+
}
223+
224+
FillDeltaStatus();
212225
}
213226

214227
/// <summary>
@@ -226,22 +239,35 @@ public void SetKeyboardInput(bool enable)
226239
/// Put the mouse location in the statusbar
227240
/// </summary>
228241
/// <param name="mouseLocation"></param>
229-
private void SetCameraLocationStatus(WorldLocation location)
242+
void SetCameraLocationStatus(WorldLocation location)
230243
{
231244
SceneWindow.tileXZ.Text = string.Format(CultureInfo.InvariantCulture, "{0,-7} {1,-7}", location.TileX, location.TileZ);
232245
SceneWindow.LocationX.Text = string.Format(CultureInfo.InvariantCulture, "{0,3:F3} ", location.Location.X);
233246
SceneWindow.LocationY.Text = string.Format(CultureInfo.InvariantCulture, "{0,3:F3} ", location.Location.Y);
234247
SceneWindow.LocationZ.Text = string.Format(CultureInfo.InvariantCulture, "{0,3:F3} ", location.Location.Z);
235248
}
236249

237-
private void FillCursorPositionStatus(WorldLocation location)
250+
void FillCursorPositionStatus(WorldLocation location)
238251
{
239252
SceneWindow.tileXZcursor.Text = string.Format(CultureInfo.InvariantCulture, "{0,-7} {1,-7}", location.TileX, location.TileZ);
240253
SceneWindow.LocationXcursor.Text = string.Format(CultureInfo.InvariantCulture, "{0,3:F3} ", location.Location.X);
241254
SceneWindow.LocationYcursor.Text = string.Format(CultureInfo.InvariantCulture, "{0,3:F3} ", location.Location.Y);
242255
SceneWindow.LocationZcursor.Text = string.Format(CultureInfo.InvariantCulture, "{0,3:F3} ", location.Location.Z);
243256
}
244257

258+
void FillDeltaStatus()
259+
{
260+
//if (DeltaContext == null)
261+
{
262+
if (EditorState == EditorState.ObjectMoving)
263+
{
264+
SceneWindow.DeltaX.Text = DeltaX.ToString("N3", CultureInfo.InvariantCulture);
265+
SceneWindow.DeltaY.Text = DeltaY.ToString("N3", CultureInfo.InvariantCulture);
266+
SceneWindow.DeltaZ.Text = DeltaZ.ToString("N3", CultureInfo.InvariantCulture);
267+
}
268+
}
269+
}
270+
245271
public async Task SetCameraLocation(WorldLocation worldLocation)
246272
{
247273
var elevatedLocation = 0f;
@@ -260,7 +286,7 @@ public async Task SetCameraLocation(WorldLocation worldLocation)
260286
worldLocation.TileX, worldLocation.TileZ, worldLocation.Location.X, worldLocation.Location.Z, true) ?? 0;
261287
break;
262288
}
263-
worldLocation.Location.Y = elevatedLocation + 15;
289+
worldLocation.Location.Y = elevatedLocation + 50;
264290
Camera.SetLocation(worldLocation);
265291

266292
var lastView = UndoStack.Count > 0 ?
@@ -284,6 +310,80 @@ public async Task SetCameraLocation(WorldLocation worldLocation)
284310
});
285311
}
286312

313+
Matrix GetMovingMatrix(in WorldPosition originalPosition, in WorldPosition handleOriginalPosition = null, WorldPosition handlePosition = null)
314+
{
315+
var handle = handleOriginalPosition ?? originalPosition;
316+
var xnaMatrix = originalPosition.XNAMatrix;
317+
318+
if (UserInput.IsDown(UserCommand.EditorLockRotation))
319+
{
320+
var distance = WorldLocation.GetDistance(handle.WorldLocation, CursorLocation);
321+
distance.Z *= -1;
322+
323+
var angle = MathHelper.WrapAngle((float)(Math.Atan2(originalPosition.XNAMatrix.M13, originalPosition.XNAMatrix.M33) - Math.Atan2(distance.Z, distance.X)));
324+
var rotation = Matrix.CreateFromYawPitchRoll(angle, 0, 0);
325+
var translation = handle.XNAMatrix.Translation;
326+
xnaMatrix.Translation -= translation;
327+
xnaMatrix *= rotation;
328+
xnaMatrix.Translation += translation;
329+
330+
if (handlePosition != null && handleOriginalPosition != null)
331+
{
332+
angle = MathHelper.WrapAngle((float)(Math.Atan2(handleOriginalPosition.XNAMatrix.M13, handleOriginalPosition.XNAMatrix.M33) - Math.Atan2(distance.Z, distance.X)));
333+
rotation = Matrix.CreateFromYawPitchRoll(angle, 0, 0);
334+
var handleMatrix = handleOriginalPosition.XNAMatrix;
335+
handleMatrix.Translation -= translation;
336+
handleMatrix *= rotation;
337+
handleMatrix.Translation += translation;
338+
handlePosition.XNAMatrix = handleMatrix;
339+
}
340+
}
341+
else
342+
{
343+
var distance = WorldLocation.GetDistance(originalPosition.WorldLocation, CursorLocation);
344+
distance.Z *= -1;
345+
346+
var axisX = Vector3.Normalize(handle.XNAMatrix.Right);
347+
var axisY = Vector3.Normalize(handle.XNAMatrix.Up);
348+
var axisZ = Vector3.Normalize(handle.XNAMatrix.Backward);
349+
350+
var tileLocation = xnaMatrix.Translation;
351+
352+
if (UserInput.IsDown(UserCommand.EditorLockOrthogonal))
353+
{
354+
var distanceX = Vector3.Dot(axisX, distance);
355+
var distanceZ = Vector3.Dot(axisZ, distance);
356+
357+
tileLocation += Math.Abs(distanceX) > Math.Abs(distanceZ) ? distanceX * axisX : distanceZ * axisZ;
358+
}
359+
else
360+
{
361+
tileLocation.X += distance.X;
362+
tileLocation.Z += distance.Z;
363+
}
364+
365+
if (!UserInput.IsDown(UserCommand.EditorLockElevation))
366+
{
367+
tileLocation.Y = Viewer.Tiles.GetElevation(handle.TileX, handle.TileZ, tileLocation.X, -tileLocation.Z);
368+
}
369+
xnaMatrix.Translation = tileLocation;
370+
371+
distance = xnaMatrix.Translation - originalPosition.XNAMatrix.Translation;
372+
373+
if (handlePosition != null && handleOriginalPosition != null)
374+
{
375+
var handleMatrix = handleOriginalPosition.XNAMatrix;
376+
handleMatrix.Translation += distance;
377+
handlePosition.XNAMatrix = handleMatrix;
378+
}
379+
380+
DeltaX = Vector3.Dot(axisX, distance);
381+
DeltaY = Vector3.Dot(axisY, distance);
382+
DeltaZ = Vector3.Dot(axisZ, distance);
383+
}
384+
return xnaMatrix;
385+
}
386+
287387
void UpdateViewUndoState()
288388
{
289389
if (UndoStack.Count == 0)
@@ -359,12 +459,28 @@ void UndoRedo(UndoDataSet undoDataSet, bool undo)
359459
undo ? undoDataSet.OldCameraRotationXRadians : undoDataSet.NewCameraRotationXRadians,
360460
undo ? undoDataSet.OldCameraRotationYRadians : undoDataSet.NewCameraRotationYRadians);
361461
}
462+
else if (undoDataSet.UndoEvent == UndoEvent.WorldObjectChanged)
463+
{
464+
if (undo)
465+
{
466+
var newPosition = new WorldPosition(undoDataSet.ChangedStaticShape.Location);
467+
undoDataSet.ChangedStaticShape.Location.CopyFrom(undoDataSet.OldPosition);
468+
undoDataSet.OldPosition.CopyFrom(newPosition);
469+
}
470+
else
471+
{
472+
473+
}
474+
}
362475
}
363476

364477
void StartObjectMove()
365478
{
366479
MovedObject = SelectedObject;
367480
MovedObjectOriginalPosition = new WorldPosition(MovedObject.Location);
481+
if (HandlePosition != null)
482+
HandleOriginalPosition = new WorldPosition(HandlePosition);
483+
DeltaContext = null;
368484
EditorState = EditorState.ObjectMoving;
369485
}
370486

@@ -377,30 +493,51 @@ void CancelObjectMove()
377493

378494
void ApplyObjectMove()
379495
{
496+
UndoStack.Push(new UndoDataSet()
497+
{
498+
UndoEvent = UndoEvent.WorldObjectChanged,
499+
TileX = MovedObject.Location.TileX,
500+
TileZ = MovedObject.Location.TileZ,
501+
Uid = MovedObject.Uid,
502+
ChangedStaticShape = MovedObject,
503+
OldPosition = MovedObjectOriginalPosition,
504+
MovedWithRespectTo = HandlePosition ?? MovedObject.Location,
505+
});
506+
RedoStack.Clear();
507+
508+
DeltaContext = UndoStack.Peek();
380509
MovedObject = null;
381510
EditorState = EditorState.ObjectSelected;
382511
}
383512

384513
void StartHandleMove()
385514
{
386515
HandlePosition = new WorldPosition(SelectedObject.Location);
516+
HandleOriginalPosition = new WorldPosition(HandlePosition);
517+
DeltaContext = null;
387518
EditorState = EditorState.HandleMoving;
388519
}
389520

390521
void CancelHandleMove()
391522
{
392523
HandlePosition = null;
524+
HandleOriginalPosition = null;
393525
EditorState = EditorState.ObjectSelected;
394526
}
395527

396528
void ApplyHandleMove()
397529
{
530+
HandleOriginalPosition = new WorldPosition(HandlePosition);
398531
EditorState = EditorState.ObjectSelected;
399532
}
400533

401534
void SelectedObjectChanged()
402535
{
403536
Viewer.EditorShapes.SelectedObject = SelectedObject;
537+
Viewer.EditorShapes.MovedObject = null;
538+
Viewer.EditorShapes.HandleLocation = null;
539+
HandlePosition = null;
540+
HandleOriginalPosition = null;
404541

405542
SelectedWorldFile = Viewer.World.Scenery.WorldFiles.SingleOrDefault(w => w.TileX == SelectedObject?.Location.TileX && w.TileZ == SelectedObject?.Location.TileZ);
406543
SelectedWorldObject = SelectedWorldFile?.MstsWFile?.Tr_Worldfile?.SingleOrDefault(o => o.UID == SelectedObject?.Uid);
@@ -454,6 +591,9 @@ public class UndoDataSet
454591
public int TileX;
455592
public int TileZ;
456593
public int Uid;
594+
public StaticShape ChangedStaticShape;
595+
public WorldPosition OldPosition;
596+
public WorldPosition MovedWithRespectTo;
457597
public Orts.Formats.Msts.WorldObject OldWorldObject;
458598
public Orts.Formats.Msts.WorldObject NewWorldObject;
459599

Source/Contrib/TrackViewer/UserInterface/SceneWindow.xaml

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
<ColumnDefinition Width="58" />
3131
<ColumnDefinition Width="58" />
3232
<ColumnDefinition Width="Auto" />
33-
<ColumnDefinition Width="60" />
34-
<ColumnDefinition Width="Auto" />
35-
<ColumnDefinition Width="*"/>
33+
<ColumnDefinition Width="63" />
34+
<ColumnDefinition Width="63" />
35+
<ColumnDefinition Width="63"/>
3636
</Grid.ColumnDefinitions>
3737
</Grid>
3838
</ItemsPanelTemplate>
@@ -97,29 +97,47 @@
9797
</TextBlock>
9898
</StatusBarItem>
9999
<Separator Grid.Column="11"/>
100-
<Separator Grid.Column="13"/>
100+
<StatusBarItem Grid.Column="12">
101+
<Border BorderThickness="1 1 0 0" BorderBrush="Gray">
102+
<Border BorderThickness="0 0 1 1" BorderBrush="AntiqueWhite">
103+
<TextBlock Name="DeltaX" Width="55" TextAlignment="Right" Background="#FFF7DCDC"/>
104+
</Border>
105+
</Border>
106+
</StatusBarItem>
107+
<StatusBarItem Grid.Column="13">
108+
<Border BorderThickness="1 1 0 0" BorderBrush="Gray">
109+
<Border BorderThickness="0 0 1 1" BorderBrush="AntiqueWhite">
110+
<TextBlock Name="DeltaY" Width="55" TextAlignment="Right" Background="#FFC3CFFB"/>
111+
</Border>
112+
</Border>
113+
</StatusBarItem>
101114
<StatusBarItem Grid.Column="14">
102-
<TextBlock Name="statusAdditional" ToolTip="Any other relevant information. Make your choice via Statusbar menu"/>
115+
<Border BorderThickness="1 1 0 0" BorderBrush="Gray">
116+
<Border BorderThickness="0 0 1 1" BorderBrush="AntiqueWhite">
117+
<TextBlock Name="DeltaZ" Width="55" TextAlignment="Right" Background="#FFCDF9D8"/>
118+
</Border>
119+
</Border>
103120
</StatusBarItem>
104121
</StatusBar>
105122
<Border BorderThickness="2">
106123
<StackPanel Orientation="Vertical" Width="150">
107124
<TextBox FontWeight="Bold" Name="Filename" Text="{Binding SelectedWorldObject.FileName}"/>
108-
<DockPanel>
109-
<TextBlock Text="UID: " PreviewTextInput="UintValidationTextBox"/>
110-
<TextBlock Name="Uid" Text="{Binding SelectedWorldObject.UID}"/>
111-
</DockPanel>
112125
<Grid>
126+
<Grid.RowDefinitions>
127+
<RowDefinition Height="Auto" />
128+
<RowDefinition Height="Auto" />
129+
</Grid.RowDefinitions>
113130
<Grid.ColumnDefinitions>
114-
<ColumnDefinition Width="Auto"/>
115131
<ColumnDefinition Width="*"/>
116-
<ColumnDefinition Width="Auto"/>
117132
<ColumnDefinition Width="*"/>
133+
<ColumnDefinition Width="0.7*"/>
118134
</Grid.ColumnDefinitions>
119-
<TextBlock Grid.Column="0" Text="Tile X: " />
120-
<TextBox Grid.Column="1" Name="TileX" PreviewTextInput="IntValidationTextBox" Text="{Binding SelectedObject.Location.TileX}" />
121-
<TextBlock Grid.Column="2" Text=" Z: " />
122-
<TextBox Grid.Column="3" Name="TileZ" PreviewTextInput="IntValidationTextBox" Text="{Binding SelectedObject.Location.TileZ}" />
135+
<TextBlock Grid.Row="0" Grid.Column="0" Text="Tile X" HorizontalAlignment="Center"/>
136+
<TextBlock Grid.Row="0" Grid.Column="1" Text="Tile Z" HorizontalAlignment="Center"/>
137+
<TextBlock Grid.Row="0" Grid.Column="2" Text="UID" HorizontalAlignment="Center"/>
138+
<TextBox Grid.Row="1" Grid.Column="0" Name="TileX" TextAlignment="Center"/>
139+
<TextBox Grid.Row="1" Grid.Column="1" Name="TileZ" TextAlignment="Center"/>
140+
<TextBox Grid.Row="1" Grid.Column="2" Name="Uid" TextAlignment="Center"/>
123141
</Grid>
124142
<Grid>
125143
<Grid.RowDefinitions>

0 commit comments

Comments
 (0)