using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace MLEM.Extensions {
///
/// A set of extensions for dealing with and
///
public static class GraphicsExtensions {
private static int lastWidth;
private static int lastHeight;
///
/// Sets the graphics device manager to fullscreen, properly taking into account the preferred backbuffer width and height to avoid lower resolutions for higher resolution screens.
///
/// The graphics device manager
/// True if fullscreen should be enabled, false if disabled
/// Thrown when changing out of fullscreen mode before changing into fullscreen mode using this method
public static void SetFullscreen(this GraphicsDeviceManager manager, bool fullscreen) {
manager.IsFullScreen = fullscreen;
if (fullscreen) {
var view = manager.GraphicsDevice.Viewport;
GraphicsExtensions.lastWidth = view.Width;
GraphicsExtensions.lastHeight = view.Height;
var curr = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode;
manager.PreferredBackBufferWidth = curr.Width;
manager.PreferredBackBufferHeight = curr.Height;
} else {
if (GraphicsExtensions.lastWidth <= 0 || GraphicsExtensions.lastHeight <= 0)
throw new InvalidOperationException("Can't call SetFullscreen to change out of fullscreen mode without going into fullscreen mode first");
manager.PreferredBackBufferWidth = GraphicsExtensions.lastWidth;
manager.PreferredBackBufferHeight = GraphicsExtensions.lastHeight;
}
manager.ApplyChanges();
}
///
/// Save version of that doesn't reset window size to defaults
///
/// The graphics device manager
public static void ApplyChangesSafely(this GraphicsDeviceManager manager) {
// If we don't do this, then applying changes will cause the
// graphics device manager to reset the window size to the
// size set when starting the game :V
var view = manager.GraphicsDevice.Viewport;
manager.PreferredBackBufferWidth = view.Width;
manager.PreferredBackBufferHeight = view.Height;
manager.ApplyChanges();
}
///
/// Resets preferred width and height back to the window's default bound values.
///
/// The graphics device manager
/// The window whose bounds to use
public static void ResetWidthAndHeight(this GraphicsDeviceManager manager, GameWindow window) {
var (width, height) = (window.ClientBounds.Width, window.ClientBounds.Height);
manager.PreferredBackBufferWidth = Math.Max(height, width);
manager.PreferredBackBufferHeight = Math.Min(height, width);
manager.ApplyChanges();
}
///
/// Starts a new using the specified render target.
/// The returned context automatically disposes when used in a using statement, which causes any previously applied render targets to be reapplied automatically.
///
/// The graphics device
/// The render target to apply
///
public static TargetContext WithRenderTarget(this GraphicsDevice device, RenderTarget2D target) {
return new TargetContext(device, target);
}
///
/// Represents a context in which a is applied.
/// This class should be used with .
///
public readonly struct TargetContext : IDisposable {
private readonly GraphicsDevice device;
private readonly RenderTargetBinding[] lastTargets;
///
/// Creates a new target context with the given settings.
///
/// The graphics device to apply the target on
/// The target to apply
public TargetContext(GraphicsDevice device, RenderTarget2D target) {
this.device = device;
#if FNA
// RenderTargetCount doesn't exist in FNA but we still want the optimization in MG
this.lastTargets = device.GetRenderTargets();
#else
this.lastTargets = device.RenderTargetCount <= 0 ? null : device.GetRenderTargets();
#endif
device.SetRenderTarget(target);
}
///
/// Disposes this target context, which causes the graphics device's previous render targets to be re-applied.
///
public void Dispose() {
this.device.SetRenderTargets(this.lastTargets);
}
}
}
}