Skip to content

Commit

Permalink
Automatic merge of T1.5.1-757-gef6c1a8c8 and 17 pull requests
Browse files Browse the repository at this point in the history
- Pull request #570 at 3539862: Experimental glTF 2.0 support with PBR lighting
- Pull request #839 at d00beb9: First phase of https://blueprints.launchpad.net/or/+spec/additional-cruise-control-parameters
- Pull request #874 at f8dbeab: Dynamic brake controller refactoring
- Pull request #875 at 43bf33e: Bug fix for https://bugs.launchpad.net/or/+bug/2036346 Player train switching doesn't work with 3D cabs
- Pull request #876 at f92de76: docs: add source for documents previously on website to source Documentation folder
- Pull request #882 at a055bca: Blueprint/train car operations UI window
- Pull request #885 at c81447b: feat: Add notifications to Menu
- Pull request #886 at 1b88d7a: Scene viewer extension to TrackViewer
- Pull request #888 at b20b888: docs: Document player application model
- Pull request #892 at 1f5ba4c: Signal Function OPP_SIG_ID_TRAINPATH
- Pull request #893 at bf8876b: Signal errors
- Pull request #894 at 5ff1e73: Correct Decrease Colour
- Pull request #896 at 5866028: First implementation of https://blueprints.launchpad.net/or/+spec/specific-sounds-for-ai-trains
- Pull request #897 at 0a9d939: feat: Improved system information collection
- Pull request #898 at e271395: Extra line with all the arguments for debugging purposes in logfile
- Pull request #899 at be2319c: Duplex steam engines - Booster Engine addition
- Pull request #900 at 42ea7ad: DMI updates
  • Loading branch information
openrails-bot committed Dec 9, 2023
Show file tree
Hide file tree
Showing 3 changed files with 270 additions and 62 deletions.
34 changes: 22 additions & 12 deletions Source/Contrib/TrackViewer/UserInterface/SceneView.xaml
Expand Up @@ -10,28 +10,38 @@
<CommandBinding Command="Undo" Executed="UndoCommand" CanExecute="UndoRedoCanExecute"/>
<CommandBinding Command="Redo" Executed="RedoCommand" CanExecute="UndoRedoCanExecute"/>
<CommandBinding Command="Stop" Executed="CancelCommand"/>
<CommandBinding Command="MoveLeft" Executed="RotateCommand"/>
<CommandBinding Command="MoveRight" Executed="MoveCommand"/>
<CommandBinding Command="MoveUp" Executed="MoveHandleCommand"/>
<CommandBinding Command="{x:Static local:SceneView.Rotate}" Executed="RotateCommand"/>
<CommandBinding Command="{x:Static local:SceneView.Move}" Executed="MoveCommand"/>
<CommandBinding Command="{x:Static local:SceneView.MoveHandle}" Executed="MoveHandleCommand"/>
<CommandBinding Command="{x:Static local:SceneView.ToggleOrtho}" Executed="ToggleOrthoCommand"/>
<CommandBinding Command="{x:Static local:SceneView.ToggleElevationLock}" Executed="ToggleElevationLockCommand"/>
<CommandBinding Command="{x:Static local:SceneView.ToggleObjectSnap}" Executed="ToggleObjectSnapCommand"/>
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Key="Esc" Command="Stop"/><!--This doesn't work-->
<KeyBinding Key="M" Command="MoveRight"/>
<KeyBinding Key="R" Command="MoveLeft"/>
<KeyBinding Key="H" Command="MoveUp"/>
<KeyBinding Key="Esc" Command="Stop"/><!--This one doesn't work, Escape is eaten somewhere, need to workaround it in code-->
<KeyBinding Key="R" Command="{x:Static local:SceneView.Rotate}"/>
<KeyBinding Key="M" Command="{x:Static local:SceneView.Move}"/>
<KeyBinding Key="H" Command="{x:Static local:SceneView.MoveHandle}"/>
<KeyBinding Key="F3" Command="{x:Static local:SceneView.ToggleObjectSnap}"/>
<KeyBinding Key="F7" Command="{x:Static local:SceneView.ToggleElevationLock}"/>
<KeyBinding Key="F8" Command="{x:Static local:SceneView.ToggleOrtho}"/>
</Window.InputBindings>
<DockPanel LastChildFill="True">
<Menu DockPanel.Dock="Top" Height="22" Name="menuMain" Width="Auto">
<MenuItem Header="_File">
<MenuItem Header="Nothing to see here" Name="menuNothing" />
</MenuItem>
<MenuItem Header="_Edit">
<MenuItem Header="_Undo" Name="menuUndo" Command="Undo" InputGestureText="Ctrl+Z"/>
<MenuItem Header="_Redo" Name="menuRedo" Command="Redo" InputGestureText="Ctrl+Y"/>
<MenuItem Header="_Undo" Command="Undo" InputGestureText="Ctrl+Z"/>
<MenuItem Header="_Redo" Command="Redo" InputGestureText="Ctrl+Y"/>
<Separator/>
<MenuItem Header="_Move" Name="menuName" Command="MoveRight" InputGestureText="M"/>
<MenuItem Header="_Rotate" Name="menuRotate" Command="MoveLeft" InputGestureText="R"/>
<MenuItem Header="Move _handle" Name="menuHandle" Command="MoveUp" InputGestureText="H"/>
<MenuItem Header="_Move" Command="{x:Static local:SceneView.Move}" InputGestureText="M"/>
<MenuItem Header="_Rotate" Command="{x:Static local:SceneView.Rotate}" InputGestureText="R"/>
<MenuItem Header="Move _Handle" Command="{x:Static local:SceneView.MoveHandle}" InputGestureText="H"/>
<Separator/>
<MenuItem Header="Ortho Mode X-Z" Command="{x:Static local:SceneView.ToggleOrtho}" InputGestureText="F8"/>
<MenuItem Header="Elevation Lock Y" Command="{x:Static local:SceneView.ToggleElevationLock}" InputGestureText="F7"/>
<MenuItem Header="Object Snap" Command="{x:Static local:SceneView.ToggleObjectSnap}" InputGestureText="F3" IsCheckable="True"/>
</MenuItem>
<MenuItem Header="_View">
<MenuItem Header="Nothing to see here" Name="menuNothing3" />
Expand Down
161 changes: 118 additions & 43 deletions Source/Contrib/TrackViewer/UserInterface/SceneView.xaml.cs
Expand Up @@ -33,17 +33,32 @@ public partial class SceneView : Window
EditorState EditorState;
EditorMoveState EditorMoveState;
StaticShape SelectedObject;
StaticShape SnappedObject;
WorldFile SelectedWorldFile;
Orts.Formats.Msts.WorldObject SelectedWorldObject;
StaticShape MovedObject;
WorldPosition MovedObjectOriginalPosition;
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();
Expand All @@ -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;
}
}

Expand All @@ -102,9 +107,30 @@ 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))
{
if (snappedObject != SnappedObject)
Viewer.EditorShapes.BoundingBoxShapes.RemoveAll(s => s == SnappedObject);
SnappedObject = snappedObject;
if (!Viewer.EditorShapes.BoundingBoxShapes.Contains(SnappedObject))
Viewer.EditorShapes.BoundingBoxShapes.Add(SnappedObject);
}
else
{
Viewer.EditorShapes.BoundingBoxShapes.RemoveAll(s => s == SnappedObject);
SnappedObject = null;
}
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
{
Expand All @@ -116,6 +142,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();
Expand Down Expand Up @@ -198,39 +236,59 @@ 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;
handleMatrix *= rotation;
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);
Expand All @@ -239,7 +297,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);
Expand All @@ -252,7 +310,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);
}
Expand All @@ -270,6 +328,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;
}
Expand Down Expand Up @@ -376,6 +437,11 @@ void CancelObjectMove()
{
MovedObject.Location.CopyFrom(MovedObjectOriginalPosition);
MovedObject = null;
if (HandleOriginalPosition != null)
HandlePosition.CopyFrom(HandleOriginalPosition);
else
HandlePosition = null;
Viewer.EditorShapes.BoundingBoxShapes.Clear();
EditorState = EditorState.ObjectSelected;
}

Expand All @@ -395,6 +461,7 @@ void ApplyObjectMove()

DeltaContext = UndoStack.Peek();
MovedObject = null;
Viewer.EditorShapes.BoundingBoxShapes.Clear();
EditorState = EditorState.ObjectSelected;
}

Expand All @@ -410,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;
}

Expand All @@ -424,8 +493,10 @@ void SelectedObjectChanged()
Viewer.EditorShapes.SelectedObject = SelectedObject;
Viewer.EditorShapes.MovedObject = null;
Viewer.EditorShapes.HandleLocation = null;
Viewer.EditorShapes.BoundingBoxShapes.Clear();
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);
Expand Down Expand Up @@ -477,11 +548,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;
Expand All @@ -500,25 +566,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)
Expand Down

0 comments on commit 9bc4b45

Please sign in to comment.