One of the things I wanted to be sure to do was allow people to play my game at different resolutions and be able to switch between fullscreen, windowed, and borderless. Borderless is a big one for a lot of people as well as myself. I have noticed even since early in my project it would stutter a little bit in borderless windowed mode. It's not terrible but choppy gameplay can get slightly annoying when I want to it to be as smooth as it is in fullscreen. I know other games have always had some issue with being borderless. I just figured since my game isn't that intensive I shouldn't see much of problem.
I am using David Amador's "XNA 2D Independent Resolution Rendering" at http://www.david-amador.com/2010/03/xna-2d-independent-resolution-rendering/. It is as follows:
static class Resolution
{
static private GraphicsDeviceManager _Device = null;
static private int _Width = 800;
static private int _Height = 600;
static private int _VWidth = 1024;
static private int _VHeight = 768;
static private Matrix _ScaleMatrix;
static private bool _FullScreen = false;
static private bool _dirtyMatrix = true;
static public void Init(ref GraphicsDeviceManager device)
{
_Width = device.PreferredBackBufferWidth;
_Height = device.PreferredBackBufferHeight;
_Device = device;
_dirtyMatrix = true;
ApplyResolutionSettings();
}
static public Matrix getTransformationMatrix()
{
if (_dirtyMatrix) RecreateScaleMatrix();
return _ScaleMatrix;
}
static public void SetResolution(int Width, int Height, bool FullScreen)
{
_Width = Width;
_Height = Height;
_FullScreen = FullScreen;
ApplyResolutionSettings();
}
static public void SetVirtualResolution(int Width, int Height)
{
_VWidth = Width;
_VHeight = Height;
_dirtyMatrix = true;
}
static private void ApplyResolutionSettings()
{
#if XBOX360
_FullScreen = true;
#endif
// If we aren't using a full screen mode, the height and width of the window can
// be set to anything equal to or smaller than the actual screen size.
if (_FullScreen == false)
{
if ((_Width <= GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width)
&& (_Height <= GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height))
{
_Device.PreferredBackBufferWidth = _Width;
_Device.PreferredBackBufferHeight = _Height;
_Device.IsFullScreen = _FullScreen;
_Device.ApplyChanges();
}
}
else
{
// If we are using full screen mode, we should check to make sure that the display
// adapter can handle the video mode we are trying to set. To do this, we will
// iterate through the display modes supported by the adapter and check them against
// the mode we want to set.
foreach (DisplayMode dm in GraphicsAdapter.DefaultAdapter.SupportedDisplayModes)
{
// Check the width and height of each mode against the passed values
if ((dm.Width == _Width) && (dm.Height == _Height))
{
// The mode is supported, so set the buffer formats, apply changes and return
_Device.PreferredBackBufferWidth = _Width;
_Device.PreferredBackBufferHeight = _Height;
_Device.IsFullScreen = _FullScreen;
_Device.ApplyChanges();
}
}
}
_dirtyMatrix = true;
_Width = _Device.PreferredBackBufferWidth;
_Height = _Device.PreferredBackBufferHeight;
}
/// <summary>
/// Sets the device to use the draw pump
/// Sets correct aspect ratio
/// </summary>
static public void BeginDraw()
{
// Start by reseting viewport to (0,0,1,1)
FullViewport();
// Clear to Black
_Device.GraphicsDevice.Clear(Color.Black);
// Calculate Proper Viewport according to Aspect Ratio
ResetViewport();
// and clear that
// This way we are gonna have black bars if aspect ratio requires it and
// the clear color on the rest
_Device.GraphicsDevice.Clear(Color.CornflowerBlue);
}
static private void RecreateScaleMatrix()
{
_dirtyMatrix = false;
_ScaleMatrix = Matrix.CreateScale(
(float)_Device.GraphicsDevice.Viewport.Width / _VWidth,
(float)_Device.GraphicsDevice.Viewport.Width / _VWidth,
1f);
}
static public void FullViewport()
{
Viewport vp = new Viewport();
vp.X = vp.Y = 0;
vp.Width = _Width;
vp.Height = _Height;
_Device.GraphicsDevice.Viewport = vp;
}
/// <summary>
/// Get virtual Mode Aspect Ratio
/// </summary>
/// <returns>aspect ratio</returns>
static public float getVirtualAspectRatio()
{
return (float)_VWidth / (float)_VHeight;
}
static public void ResetViewport()
{
float targetAspectRatio = getVirtualAspectRatio();
// figure out the largest area that fits in this resolution at the desired aspect ratio
int width = _Device.PreferredBackBufferWidth;
int height = (int)(width / targetAspectRatio + .5f);
bool changed = false;
if (height > _Device.PreferredBackBufferHeight)
{
height = _Device.PreferredBackBufferHeight;
// PillarBox
width = (int)(height * targetAspectRatio + .5f);
changed = true;
}
// set up the new viewport centered in the backbuffer
Viewport viewport = new Viewport();
viewport.X = (_Device.PreferredBackBufferWidth / 2) - (width / 2);
viewport.Y = (_Device.PreferredBackBufferHeight / 2) - (height / 2);
viewport.Width = width;
viewport.Height = height;
viewport.MinDepth = 0;
viewport.MaxDepth = 1;
if (changed)
{
_dirtyMatrix = true;
}
_Device.GraphicsDevice.Viewport = viewport;
}
}
I use the following to set up the window's initial parameters:
Resolution.Init(ref graphics);
Resolution.SetVirtualResolution(GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width, GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height);
Resolution.SetResolution(GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width, GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height, false);
I can toggle between false and true to set fullscreen or windowed. The trouble comes next when I create my gameplay screen and use the following to create a borderless window:
Form gameForm = (Form)Form.FromHandle(curGame.control.Handle);
gameForm.FormBorderStyle = FormBorderStyle.None;
If I have it set to fullscreen through Resolution then this borderless code doesn't seem to do anything at all. If I have it set to windowed it does work as expected and creates a borderless window. The only problem is that strange lag/choppy behavior. In full screen it doesn't lag one bit so I'm wondering if there's some issue with how Resolution and the borderless code work. Is how I'm doing a borderless window correct? Am I just going to have to deal with a little bit of stuttering in that mode? I'd appreciate any insight!