BoxingViewportAdapter.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. using System;
  2. using Microsoft.Xna.Framework;
  3. using Microsoft.Xna.Framework.Graphics;
  4. // ReSharper disable once CheckNamespace
  5. namespace MonoGame.Extended.ViewportAdapters
  6. {
  7. public enum BoxingMode
  8. {
  9. None,
  10. Letterbox,
  11. Pillarbox
  12. }
  13. public class BoxingViewportAdapter : ScalingViewportAdapter
  14. {
  15. private readonly GameWindow _window;
  16. private readonly GraphicsDevice _graphicsDevice;
  17. /// <summary>
  18. /// Initializes a new instance of the <see cref="BoxingViewportAdapter" />.
  19. /// </summary>
  20. public BoxingViewportAdapter(GameWindow window, GraphicsDevice graphicsDevice, int virtualWidth, int virtualHeight, int horizontalBleed = 0, int verticalBleed = 0)
  21. : base(graphicsDevice, virtualWidth, virtualHeight)
  22. {
  23. _window = window;
  24. _graphicsDevice = graphicsDevice;
  25. window.ClientSizeChanged += OnClientSizeChanged;
  26. HorizontalBleed = horizontalBleed;
  27. VerticalBleed = verticalBleed;
  28. }
  29. public override void Dispose()
  30. {
  31. _window.ClientSizeChanged -= OnClientSizeChanged;
  32. base.Dispose();
  33. }
  34. /// <summary>
  35. /// Size of horizontal bleed areas (from left and right edges) which can be safely cut off
  36. /// </summary>
  37. public int HorizontalBleed { get; }
  38. /// <summary>
  39. /// Size of vertical bleed areas (from top and bottom edges) which can be safely cut off
  40. /// </summary>
  41. public int VerticalBleed { get; }
  42. public BoxingMode BoxingMode { get; private set; }
  43. private void OnClientSizeChanged(object sender, EventArgs eventArgs)
  44. {
  45. var clientBounds = _window.ClientBounds;
  46. var worldScaleX = (float)clientBounds.Width / VirtualWidth;
  47. var worldScaleY = (float)clientBounds.Height / VirtualHeight;
  48. var safeScaleX = (float)clientBounds.Width / (VirtualWidth - HorizontalBleed);
  49. var safeScaleY = (float)clientBounds.Height / (VirtualHeight - VerticalBleed);
  50. var worldScale = MathHelper.Max(worldScaleX, worldScaleY);
  51. var safeScale = MathHelper.Min(safeScaleX, safeScaleY);
  52. var scale = MathHelper.Min(worldScale, safeScale);
  53. var width = (int)(scale * VirtualWidth + 0.5f);
  54. var height = (int)(scale * VirtualHeight + 0.5f);
  55. if (height >= clientBounds.Height && width < clientBounds.Width)
  56. BoxingMode = BoxingMode.Pillarbox;
  57. else
  58. {
  59. if (width >= clientBounds.Height && height <= clientBounds.Height)
  60. BoxingMode = BoxingMode.Letterbox;
  61. else
  62. BoxingMode = BoxingMode.None;
  63. }
  64. var x = clientBounds.Width / 2 - width / 2;
  65. var y = clientBounds.Height / 2 - height / 2;
  66. GraphicsDevice.Viewport = new Viewport(x, y, width, height);
  67. }
  68. public override void Reset()
  69. {
  70. base.Reset();
  71. OnClientSizeChanged(this, EventArgs.Empty);
  72. }
  73. public override Point PointToScreen(int x, int y)
  74. {
  75. var viewport = GraphicsDevice.Viewport;
  76. return base.PointToScreen(x - viewport.X, y - viewport.Y);
  77. }
  78. }
  79. }