Skip to content

Commit 40f7f86

Browse files
committed
Added selection possibility
1 parent 7c4922e commit 40f7f86

File tree

20 files changed

+494
-173
lines changed

20 files changed

+494
-173
lines changed

Source/Contrib/TrackViewer/SceneViewer.cs

Lines changed: 94 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
using Orts.Viewer3D.Processes;
4040
using System.Threading;
4141
using System.Threading.Tasks;
42+
using System.IO;
43+
using System.Globalization;
4244

4345
namespace ORTS.TrackViewer
4446
{
@@ -48,8 +50,9 @@ public class SceneViewer
4850

4951
public SceneWindow SceneWindow;
5052
public GameWindow SwapChainWindow;
51-
TrackViewer TrackViewer;
53+
public readonly TrackViewer TrackViewer;
5254
SwapChainRenderTarget SwapChain;
55+
internal StaticShape SelectedObject;
5356

5457
/// <summary>The command-line arguments</summary>
5558
private string[] CommandLineArgs;
@@ -107,8 +110,7 @@ public SceneViewer(TrackViewer trackViewer, string[] args)
107110
/// <summary>
108111
/// Allows the game to perform any initialization it needs to before starting to run.
109112
/// This is where it can query for any required services and load any non-graphic
110-
/// relation ontent. Calling base.Initialize will enumerate through any components
111-
/// and initialize them as well.
113+
/// relation ontent.
112114
/// </summary>
113115
public void Initialize()
114116
{
@@ -130,17 +132,17 @@ public void LoadContent()
130132
/// <param name="gameTime">Provides a snapshot of timing values.</param>
131133
public void Update(GameTime gameTime)
132134
{
135+
if (UserInput.IsMouseLeftButtonPressed && UserInput.ModifiersMaskShiftCtrlAlt(false, false, false))
136+
{
137+
if (PickByMouse(out SelectedObject))
138+
{
139+
TrackViewer.RenderProcess.Viewer.EditorShapes.SelectedObject = SelectedObject;
140+
FillSelectedObjectData();
141+
}
142+
}
133143
SetCameraLocationStatus(TrackViewer.RenderProcess?.Viewer?.Camera?.CameraWorldLocation ?? new WorldLocation());
134144
}
135145

136-
/// <summary>
137-
/// This is called when the game should draw itself.
138-
/// </summary>
139-
/// <param name="gameTime">Provides a snapshot of timing values.</param>
140-
public void Draw(GameTime gameTime)
141-
{
142-
}
143-
144146
public void EndDraw()
145147
{
146148
SwapChain.Present();
@@ -195,6 +197,87 @@ public async Task SetCameraLocation()
195197
mouseLocation.Location.Y = elevatedLocation + 15;
196198
TrackViewer.RenderProcess.Viewer.ViewerCamera.SetLocation(mouseLocation);
197199
}
200+
201+
protected bool PickByMouse(out StaticShape pickedObject)
202+
{
203+
var viewer = TrackViewer.RenderProcess.Viewer;
204+
205+
if (viewer == null)
206+
{
207+
pickedObject = null;
208+
return false;
209+
}
210+
211+
var camera = viewer.Camera;
212+
213+
var direction = Vector3.Normalize(viewer.FarPoint - viewer.NearPoint);
214+
var pickRay = new Ray(viewer.NearPoint, direction);
215+
216+
pickedObject = null;
217+
var pickedDistance = float.MaxValue;
218+
foreach (var worldFile in viewer.World.Scenery.WorldFiles)
219+
{
220+
foreach (var sceneryObject in worldFile.sceneryObjects)
221+
{
222+
float? distance = null;
223+
224+
if (sceneryObject.BoundingBox is Orts.Viewer3D.BoundingBox boundingBox)
225+
{
226+
// Locate relative to the camera
227+
var dTileX = sceneryObject.Location.TileX - camera.TileX;
228+
var dTileZ = sceneryObject.Location.TileZ - camera.TileZ;
229+
var xnaDTileTranslation = sceneryObject.Location.XNAMatrix;
230+
xnaDTileTranslation.M41 += dTileX * 2048;
231+
xnaDTileTranslation.M43 -= dTileZ * 2048;
232+
233+
var min = Vector3.Transform(boundingBox.Min, xnaDTileTranslation);
234+
var max = Vector3.Transform(boundingBox.Max, xnaDTileTranslation);
235+
236+
var xnabb = new Microsoft.Xna.Framework.BoundingBox(min, max);
237+
distance = pickRay.Intersects(xnabb);
238+
}
239+
else
240+
{
241+
var radius = 10f;
242+
var boundingSphere = new BoundingSphere(camera.XnaLocation(sceneryObject.Location.WorldLocation), radius);
243+
distance = pickRay.Intersects(boundingSphere);
244+
}
245+
246+
if (distance != null)
247+
{
248+
if (distance < pickedDistance)
249+
{
250+
pickedDistance = distance.Value;
251+
pickedObject = sceneryObject;
252+
}
253+
}
254+
}
255+
}
256+
return pickedObject != null;
257+
}
258+
259+
void FillSelectedObjectData()
260+
{
261+
SceneWindow.Filename.Text = SelectedObject != null ? System.IO.Path.GetFileName(SelectedObject.SharedShape.FilePath) : "";
262+
SceneWindow.TileX.Text = SelectedObject?.Location.TileX.ToString(CultureInfo.InvariantCulture).Replace(",", "");
263+
SceneWindow.TileZ.Text = SelectedObject?.Location.TileZ.ToString(CultureInfo.InvariantCulture).Replace(",", "");
264+
SceneWindow.PosX.Text = SelectedObject?.Location.Location.X.ToString("N3", CultureInfo.InvariantCulture).Replace(",", "");
265+
SceneWindow.PosY.Text = SelectedObject?.Location.Location.Y.ToString("N3", CultureInfo.InvariantCulture).Replace(",", "");
266+
SceneWindow.PosZ.Text = SelectedObject?.Location.Location.Z.ToString("N3", CultureInfo.InvariantCulture).Replace(",", "");
267+
if (SelectedObject?.Location.XNAMatrix.Decompose(out var _, out var q, out var _) ?? false)
268+
{
269+
var mag = Math.Sqrt(q.W * q.W + q.Y * q.Y);
270+
var w = q.W / mag;
271+
var ang = 2.0 * Math.Acos(w) / Math.PI * 180;
272+
SceneWindow.RotY.Text = ang.ToString("N3", CultureInfo.InvariantCulture).Replace(",", "");
273+
}
274+
else
275+
{
276+
SceneWindow.RotY.Text = "";
277+
}
278+
SceneWindow.Uid.Text = SelectedObject.Uid.ToString(CultureInfo.InvariantCulture).Replace(",", "");
279+
}
280+
198281
}
199282

200283
public class SceneViewerHwndHost : HwndHost
@@ -225,24 +308,6 @@ protected override HandleRef BuildWindowCore(HandleRef hwndParent)
225308

226309
protected override void DestroyWindowCore(HandleRef hwnd)
227310
{
228-
229-
}
230-
}
231-
232-
public class SceneViewerVisualHost : UIElement
233-
{
234-
System.Windows.Media.Visual Visual;
235-
236-
public SceneViewerVisualHost(GameWindow gameWindow)
237-
{
238-
Visual = HwndSource.FromHwnd(gameWindow.Handle).RootVisual;
239-
}
240-
241-
protected override int VisualChildrenCount { get { return Visual != null ? 1 : 0; } }
242-
243-
protected override System.Windows.Media.Visual GetVisualChild(int index)
244-
{
245-
return Visual;
246311
}
247312
}
248313
}

Source/Contrib/TrackViewer/TrackViewer.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,6 @@ protected override void Update(GameTime gameTime)
557557
protected override void Draw(GameTime gameTime)
558558
{
559559
graphics.GraphicsDevice.SetRenderTarget(null);
560-
SceneViewer?.Draw(gameTime);
561560

562561
// Even if there is nothing new to draw for main window, we might still need to draw for the shadow textures.
563562
if (DrawTrackDB != null && Properties.Settings.Default.showInset)
@@ -1253,4 +1252,17 @@ class GameStateStandBy : GameState
12531252
{
12541253
public GameStateStandBy() { }
12551254
}
1255+
1256+
class GameStateSceneViewer3D : GameStateViewer3D
1257+
{
1258+
public GameStateSceneViewer3D(Viewer viewer)
1259+
: base(viewer) { }
1260+
1261+
public override void Update(RenderFrame frame, double totalRealSeconds)
1262+
{
1263+
base.Update(frame, totalRealSeconds);
1264+
1265+
1266+
}
1267+
}
12561268
}

Source/Contrib/TrackViewer/UserInterface/SceneWindow.xaml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,51 @@
112112
<TextBlock Name="statusAdditional" ToolTip="Any other relevant information. Make your choice via Statusbar menu"/>
113113
</StatusBarItem>
114114
</StatusBar>
115+
<Border BorderThickness="2">
116+
<StackPanel Orientation="Vertical" Width="150">
117+
<TextBox Text="abcdefgh12345.s" FontWeight="Bold" Name="Filename"/>
118+
<DockPanel>
119+
<TextBlock Text="UID: " PreviewTextInput="UintValidationTextBox"/>
120+
<TextBlock Name="Uid"/>
121+
</DockPanel>
122+
<Grid>
123+
<Grid.ColumnDefinitions>
124+
<ColumnDefinition Width="Auto"/>
125+
<ColumnDefinition Width="*"/>
126+
<ColumnDefinition Width="Auto"/>
127+
<ColumnDefinition Width="*"/>
128+
</Grid.ColumnDefinitions>
129+
<TextBlock Grid.Column="0" Text="Tile X: " />
130+
<TextBox Grid.Column="1" Name="TileX" PreviewTextInput="IntValidationTextBox"></TextBox>
131+
<TextBlock Grid.Column="2" Text=" Z: " />
132+
<TextBox Grid.Column="3" Name="TileZ" PreviewTextInput="IntValidationTextBox"></TextBox>
133+
</Grid>
134+
<Grid>
135+
<Grid.RowDefinitions>
136+
<RowDefinition Height="Auto" />
137+
<RowDefinition Height="Auto" />
138+
<RowDefinition Height="Auto" />
139+
<RowDefinition Height="Auto" />
140+
</Grid.RowDefinitions>
141+
<Grid.ColumnDefinitions>
142+
<ColumnDefinition Width="Auto" />
143+
<ColumnDefinition Width="*" />
144+
<ColumnDefinition Width="*" />
145+
</Grid.ColumnDefinitions>
146+
<TextBlock Grid.Row="0" Grid.Column="1" Text="Position" HorizontalAlignment="Center"/>
147+
<TextBlock Grid.Row="0" Grid.Column="2" Text="Rotation" HorizontalAlignment="Center"/>
148+
<TextBlock Grid.Row="1" Text="X: "/>
149+
<TextBlock Grid.Row="2" Text="Y: "/>
150+
<TextBlock Grid.Row="3" Text="Z: "/>
151+
<TextBox Grid.Row="1" Grid.Column="1" x:Name="PosX" PreviewTextInput="FloatValidationTextBox"/>
152+
<TextBox Grid.Row="2" Grid.Column="1" x:Name="PosY" PreviewTextInput="FloatValidationTextBox"/>
153+
<TextBox Grid.Row="3" Grid.Column="1" x:Name="PosZ" PreviewTextInput="FloatValidationTextBox"/>
154+
<TextBox Grid.Row="1" Grid.Column="2" x:Name="RotX" PreviewTextInput="FloatValidationTextBox"/>
155+
<TextBox Grid.Row="2" Grid.Column="2" x:Name="RotY" PreviewTextInput="FloatValidationTextBox"/>
156+
<TextBox Grid.Row="3" Grid.Column="2" x:Name="RotZ" PreviewTextInput="FloatValidationTextBox"/>
157+
</Grid>
158+
</StackPanel>
159+
</Border>
115160
<Grid DockPanel.Dock="Bottom" x:Name="GraphicsHostElement" />
116161
</DockPanel>
117162
</Window>

Source/Contrib/TrackViewer/UserInterface/SceneWindow.xaml.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,20 @@ protected override void OnClosing(CancelEventArgs e)
3636
e.Cancel = true;
3737
Hide();
3838
}
39+
40+
private void IntValidationTextBox(object sender, TextCompositionEventArgs e)
41+
{
42+
e.Handled = int.TryParse(e.Text, out var _);
43+
}
44+
45+
private void UintValidationTextBox(object sender, TextCompositionEventArgs e)
46+
{
47+
e.Handled = uint.TryParse(e.Text, out var _);
48+
}
49+
50+
private void FloatValidationTextBox(object sender, TextCompositionEventArgs e)
51+
{
52+
e.Handled = float.TryParse(e.Text, out var _);
53+
}
3954
}
4055
}

0 commit comments

Comments
 (0)