Skip to content

Commit

Permalink
Implement letterboxing of non-fitting 2D cabs, toggleable with Ctrl+1.
Browse files Browse the repository at this point in the history
  • Loading branch information
YoRyan committed Apr 22, 2020
1 parent 22661c4 commit 31a8fa1
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 19 deletions.
1 change: 1 addition & 0 deletions Source/ORTS.Common/Input/UserCommand.cs
Expand Up @@ -75,6 +75,7 @@ public enum UserCommand
[GetString("Camera Change Passenger Viewpoint")] CameraChangePassengerViewPoint,
[GetString("Camera 3D Cab")] CameraThreeDimensionalCab,
[GetString("Camera Toggle Show Cab")] CameraToggleShowCab,
[GetString("Camera Toggle Letterbox Cab")] CameraToggleLetterboxCab,
[GetString("Camera Head Out Forward")] CameraHeadOutForward,
[GetString("Camera Head Out Backward")] CameraHeadOutBackward,
[GetString("Camera Outside Front")] CameraOutsideFront,
Expand Down
1 change: 1 addition & 0 deletions Source/ORTS.Settings/InputSettings.cs
Expand Up @@ -331,6 +331,7 @@ static void InitializeCommands(UserCommandInput[] Commands)
Commands[(int)UserCommand.CameraScrollLeft] = new UserCommandModifiableKeyInput(0x4B, KeyModifiers.Alt);
Commands[(int)UserCommand.CameraScrollRight] = new UserCommandModifiableKeyInput(0x4D, KeyModifiers.Alt);
Commands[(int)UserCommand.CameraChangePassengerViewPoint] = new UserCommandKeyInput(0x06, KeyModifiers.Shift);
Commands[(int)UserCommand.CameraToggleLetterboxCab] = new UserCommandKeyInput(0x02, KeyModifiers.Control);
Commands[(int)UserCommand.CameraToggleShowCab] = new UserCommandKeyInput(0x02, KeyModifiers.Shift);
Commands[(int)UserCommand.CameraTrackside] = new UserCommandKeyInput(0x05);
Commands[(int)UserCommand.CameraSpecialTracksidePoint] = new UserCommandKeyInput(0x05, KeyModifiers.Shift);
Expand Down
2 changes: 2 additions & 0 deletions Source/ORTS.Settings/UserSettings.cs
Expand Up @@ -339,6 +339,8 @@ public enum Menu_SelectionIndex
[Default(false)]
public bool DataLogger { get; set; }
[Default(false)]
public bool Letterbox2DCab { get; set; }
[Default(false)]
public bool Profiling { get; set; }
[Default(0)]
public int ProfilingFrameCount { get; set; }
Expand Down
5 changes: 5 additions & 0 deletions Source/RunActivity/Viewer3D/Cameras.cs
Expand Up @@ -2198,6 +2198,11 @@ public override void HandleUserInput(ElapsedTime elapsedTime)
ScrollRight(true, speed);
if (UserInput.IsDown(UserCommand.CameraScrollLeft))
ScrollRight(false, speed);
if (UserInput.IsPressed(UserCommand.CameraToggleLetterboxCab))
{
Viewer.Settings.Letterbox2DCab = !Viewer.Settings.Letterbox2DCab;
Viewer.AdjustCabHeight(Viewer.DisplaySize.X, Viewer.DisplaySize.Y);
}
}
}

Expand Down
40 changes: 39 additions & 1 deletion Source/RunActivity/Viewer3D/RollingStock/MSTSLocomotiveViewer.cs
Expand Up @@ -1282,6 +1282,10 @@ public void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
_CabRect.Width = _Viewer.CabWidthPixels;
_CabRect.Height = _Viewer.CabHeightPixels;

// Cab view position adjusted to allow for letterboxing
_CabRect.X = _Viewer.CabXLetterboxPixels;
_CabRect.Y = _Viewer.CabYLetterboxPixels;

if (_PrevScreenSize != _Viewer.DisplaySize && _Shader != null)
{
_PrevScreenSize = _Viewer.DisplaySize;
Expand Down Expand Up @@ -1335,6 +1339,24 @@ public override void Draw(GraphicsDevice graphicsDevice)
{
_SpriteShader2DCabView.SpriteBatch.Draw(_CabTexture, stretchedCab, Color.White);
}

// Draw letterboxing.
Texture2D letterboxTexture = new Texture2D(graphicsDevice, 1, 1);
letterboxTexture.SetData<Color>(new Color[] { Color.Black });
Action<int, int, int, int> drawLetterbox = (x, y, w, h) =>
{
_SpriteShader2DCabView.SpriteBatch.Draw(letterboxTexture, new Rectangle(x, y, w, h), Color.White);
};
if (_Viewer.CabXLetterboxPixels > 0)
{
drawLetterbox(0, 0, _Viewer.CabXLetterboxPixels, _Viewer.DisplaySize.Y);
drawLetterbox(_Viewer.CabXLetterboxPixels + _Viewer.CabWidthPixels, 0, _Viewer.DisplaySize.X - _Viewer.CabWidthPixels - _Viewer.CabXLetterboxPixels, _Viewer.DisplaySize.Y);
}
if (_Viewer.CabYLetterboxPixels > 0)
{
drawLetterbox(0, 0, _Viewer.DisplaySize.X, _Viewer.CabYLetterboxPixels);
drawLetterbox(0, _Viewer.CabYLetterboxPixels + _Viewer.CabHeightPixels, _Viewer.DisplaySize.X, _Viewer.DisplaySize.Y - _Viewer.CabHeightPixels - _Viewer.CabYLetterboxPixels);
}
}
}

Expand Down Expand Up @@ -1463,7 +1485,11 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
// Cab view height and vertical position adjusted to allow for clip or stretch.
Position.X = (float)Viewer.CabWidthPixels / 640 * ((float)Control.PositionX + Origin.X * Scale) - Viewer.CabXOffsetPixels;
Position.Y = (float)Viewer.CabHeightPixels / 480 * ((float)Control.PositionY + Origin.Y * Scale) + Viewer.CabYOffsetPixels;
ScaleToScreen = (float)Viewer.DisplaySize.X / 640 * Scale;
ScaleToScreen = (float)Viewer.CabWidthPixels / 640 * Scale;

// Cab view position adjusted to allow for letterboxing.
Position.X += Viewer.CabXLetterboxPixels;
Position.Y += Viewer.CabYLetterboxPixels;

var rangeFraction = GetRangeFraction();
var direction = ControlDial.Direction == 0 ? 1 : -1;
Expand Down Expand Up @@ -1650,6 +1676,10 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
else DrawColor = new Color(Gauge.PositiveColor.R, Gauge.PositiveColor.G, Gauge.PositiveColor.B, Gauge.PositiveColor.A);
}
}

// Cab view position adjusted to allow for letterboxing.
DestinationRectangle.X += Viewer.CabXLetterboxPixels;
DestinationRectangle.Y += Viewer.CabYLetterboxPixels;
}

public override void Draw(GraphicsDevice graphicsDevice)
Expand Down Expand Up @@ -1739,6 +1769,10 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
DestinationRectangle.Y = (int)(yratio * Control.PositionY * 1.0001) + Viewer.CabYOffsetPixels;
DestinationRectangle.Width = (int)(xratio * Math.Min(Control.Width, Texture.Width)); // Allow only downscaling of the texture, and not upscaling
DestinationRectangle.Height = (int)(yratio * Math.Min(Control.Height, Texture.Height)); // Allow only downscaling of the texture, and not upscaling

// Cab view position adjusted to allow for letterboxing.
DestinationRectangle.X += Viewer.CabXLetterboxPixels;
DestinationRectangle.Y += Viewer.CabYLetterboxPixels;
}

public override void Draw(GraphicsDevice graphicsDevice)
Expand Down Expand Up @@ -2117,6 +2151,10 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
DrawPosition.Width = (int)(Control.Width * Viewer.DisplaySize.X / 640);
DrawPosition.Height = (int)(Control.Height * Viewer.DisplaySize.Y / 480);

// Cab view position adjusted to allow for letterboxing.
DrawPosition.X += Viewer.CabXLetterboxPixels;
DrawPosition.Y += Viewer.CabYLetterboxPixels;

if (Control.ControlType == CABViewControlTypes.CLOCK)
{
// Clock is drawn specially.
Expand Down
52 changes: 34 additions & 18 deletions Source/RunActivity/Viewer3D/Viewer.cs
Expand Up @@ -169,9 +169,10 @@ enum VisibilityState

// MSTS cab views are images with aspect ratio 4:3.
// OR can use cab views with other aspect ratios where these are available.
// On screen with other aspect ratios (e.g. 16:9), two approaches are possible:
// On screen with other aspect ratios (e.g. 16:9), three approaches are possible:
// 1) stretch the width to fit the screen. This gives flattened controls, most noticeable with round dials.
// 2) clip the image losing a slice off top and bottom.
// 3) letterbox the image by drawing black bars in the unfilled spaces.
// Setting.Cab2DStretch controls the amount of stretch and clip. 0 is entirely clipped and 100 is entirely stretched.
// No difference is seen on screens with 4:3 aspect ratio.
// This adjustment assumes that the cab view is 4:3. Where the cab view matches the aspect ratio of the screen, use an adjustment of 100.
Expand All @@ -181,6 +182,8 @@ enum VisibilityState
public int CabXOffsetPixels { get; set; }
public int CabExceedsDisplay; // difference between cabview texture vertical resolution and display vertical resolution
public int CabExceedsDisplayHorizontally; // difference between cabview texture horizontal resolution and display vertical resolution
public int CabYLetterboxPixels { get; set; } // offset the cab when drawing it if it is smaller than the display; both coordinates should always be >= 0
public int CabXLetterboxPixels { get; set; }
public float CabTextureInverseRatio = 0.75f; // default of inverse of cab texture ratio

public CommandLog Log { get { return Simulator.Log; } }
Expand Down Expand Up @@ -618,28 +621,41 @@ public void AdjustCabHeight(int windowWidth, int windowHeight)
}
int unstretchedCabHeightPixels = (int)(CabTextureInverseRatio * windowWidth);
int unstretchedCabWidthPixels = (int)(windowHeight / CabTextureInverseRatio);
if (((float)windowHeight / windowWidth) < CabTextureInverseRatio)
float windowInverseRatio = (float)windowHeight / windowWidth;
if (Settings.Letterbox2DCab)
{
// screen is wide-screen, so can choose between vertical scroll or horizontal stretch
CabExceedsDisplay = (int)((unstretchedCabHeightPixels - windowHeight) * ((100 - Settings.Cab2DStretch) / 100f));
CabExceedsDisplayHorizontally = 0;
}
else if (((float)windowHeight / windowWidth) > CabTextureInverseRatio)
{
// must scroll horizontally
CabExceedsDisplay = 0;
CabExceedsDisplayHorizontally = unstretchedCabWidthPixels - windowWidth;
CabWidthPixels = Math.Min((int)Math.Round(windowHeight / CabTextureInverseRatio), windowWidth);
CabHeightPixels = Math.Min((int)Math.Round(windowWidth * CabTextureInverseRatio), windowHeight);
CabXLetterboxPixels = (windowWidth - CabWidthPixels) / 2;
CabYLetterboxPixels = (windowHeight - CabHeightPixels) / 2;
CabExceedsDisplay = CabExceedsDisplayHorizontally = CabXOffsetPixels = CabYOffsetPixels = 0;
}
else
{
// nice, window aspect ratio and cabview aspect ratio are identical
CabExceedsDisplay = 0;
CabExceedsDisplayHorizontally = 0;
if (windowInverseRatio == CabTextureInverseRatio)
{
// nice, window aspect ratio and cabview aspect ratio are identical
CabExceedsDisplay = 0;
CabExceedsDisplayHorizontally = 0;
}
else if (windowInverseRatio < CabTextureInverseRatio)
{
// screen is wide-screen, so can choose between vertical scroll or horizontal stretch
CabExceedsDisplay = (int)((unstretchedCabHeightPixels - windowHeight) * ((100 - Settings.Cab2DStretch) / 100f));
CabExceedsDisplayHorizontally = 0;
}
else
{
// must scroll horizontally
CabExceedsDisplay = 0;
CabExceedsDisplayHorizontally = unstretchedCabWidthPixels - windowWidth;
}
CabHeightPixels = windowHeight + CabExceedsDisplay;
CabYOffsetPixels = -CabExceedsDisplay / 2; // Initial value is halfway. User can adjust with arrow keys.
CabWidthPixels = windowWidth + CabExceedsDisplayHorizontally;
CabXOffsetPixels = CabExceedsDisplayHorizontally / 2;
CabXLetterboxPixels = CabYLetterboxPixels = 0;
}
CabHeightPixels = windowHeight + CabExceedsDisplay;
CabYOffsetPixels = -CabExceedsDisplay / 2; // Initial value is halfway. User can adjust with arrow keys.
CabWidthPixels = windowWidth + CabExceedsDisplayHorizontally;
CabXOffsetPixels = CabExceedsDisplayHorizontally / 2;
if (CabCamera.IsAvailable) CabCamera.Initialize();
}

Expand Down

0 comments on commit 31a8fa1

Please sign in to comment.