using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
using System.Threading;
namespace XNAWinForms
{
using Color = System.Drawing.Color;
using Rectangle = Microsoft.Xna.Framework.Rectangle;
public class ServiceContainer : IServiceProvider
{
Dictionary<Type, object> services = new Dictionary<Type, object>();
public void AddService<T>(T service)
{
services.Add(typeof(T), service);
}
public object GetService(Type serviceType)
{
object service;
services.TryGetValue(serviceType, out service);
return service;
}
}
class GraphicsDeviceService : IGraphicsDeviceService
{
#region Fields
static GraphicsDeviceService singletonInstance;
static int referenceCount;
#endregion
GraphicsDeviceService(IntPtr windowHandle, int width, int height)
{
parameters = new PresentationParameters();
parameters.BackBufferWidth = Math.Max(width, 1);
parameters.BackBufferHeight = Math.Max(height, 1);
parameters.BackBufferFormat = SurfaceFormat.Color;
parameters.DepthStencilFormat = DepthFormat.Depth24;
parameters.DeviceWindowHandle = windowHandle;
parameters.PresentationInterval = PresentInterval.Immediate;
parameters.IsFullScreen = false;
graphicsDevice = new GraphicsDevice(GraphicsAdapter.DefaultAdapter,
GraphicsProfile.Reach,
parameters);
}
public static GraphicsDeviceService AddRef(IntPtr windowHandle,
int width, int height)
{
if (Interlocked.Increment(ref referenceCount) == 1)
{
singletonInstance = new GraphicsDeviceService(windowHandle,
width, height);
}
return singletonInstance;
}
public void Release(bool disposing)
{
if (Interlocked.Decrement(ref referenceCount) == 0)
{
if (disposing)
{
if (DeviceDisposing != null)
DeviceDisposing(this, EventArgs.Empty);
graphicsDevice.Dispose();
}
graphicsDevice = null;
}
}
public void ResetDevice(int width, int height)
{
if (DeviceResetting != null)
DeviceResetting(this, EventArgs.Empty);
parameters.BackBufferWidth = Math.Max(parameters.BackBufferWidth, width);
parameters.BackBufferHeight = Math.Max(parameters.BackBufferHeight, height);
graphicsDevice.Reset(parameters);
if (DeviceReset != null)
DeviceReset(this, EventArgs.Empty);
}
public GraphicsDevice GraphicsDevice
{
get { return graphicsDevice; }
}
GraphicsDevice graphicsDevice;
PresentationParameters parameters;
public event EventHandler<EventArgs> DeviceCreated;
public event EventHandler<EventArgs> DeviceDisposing;
public event EventHandler<EventArgs> DeviceReset;
public event EventHandler<EventArgs> DeviceResetting;
}
abstract public class GraphicsDeviceControl : Control
{
#region Fields
GraphicsDeviceService graphicsDeviceService;
#endregion
#region Properties
public GraphicsDevice GraphicsDevice
{
get { return graphicsDeviceService.GraphicsDevice; }
}
public ServiceContainer Services
{
get { return services; }
}
ServiceContainer services = new ServiceContainer();
#endregion
#region Initialization
protected override void OnCreateControl()
{
if (!DesignMode)
{
graphicsDeviceService = GraphicsDeviceService.AddRef(Handle,ClientSize.Width,ClientSize.Height);
services.AddService<IGraphicsDeviceService>(graphicsDeviceService);
Initialize();
}
base.OnCreateControl();
}
protected override void Dispose(bool disposing)
{
if (graphicsDeviceService != null)
{
graphicsDeviceService.Release(disposing);
graphicsDeviceService = null;
}
base.Dispose(disposing);
}
#endregion
#region Paint
public bool Render(RenderTarget2D _target)
{
return Render(_target, 0, 0);
}
public bool Render(RenderTarget2D _target,int _left, int _top)
{
GraphicsDevice.SetRenderTarget(_target);
try
{
return Render(_left,_top,_target.Width, _target.Height);
}
finally
{
GraphicsDevice.SetRenderTarget(null);
}
}
public bool Render()
{
return Render(0,0);
}
public bool Render(int _left, int _top, int _width, int _height)
{
return Render(new System.Drawing.Rectangle(_left, _top, _width, _height));
}
public bool Render(int _width, int _height)
{
return Render(new System.Drawing.Rectangle(0, 0, _width, _height));
}
public bool Render(System.Drawing.Rectangle _rect)
{
string beginDrawError = "";
return Render(ref beginDrawError, _rect);
}
protected bool Render(ref string beginDrawError, System.Drawing.Rectangle _rect)
{
if (_rect.Width == 0) _rect.Width = ClientSize.Width;
if (_rect.Height == 0) _rect.Height = ClientSize.Height;
beginDrawError = BeginDraw(_rect);
if (string.IsNullOrEmpty(beginDrawError))
{
Draw();
EndDraw();
return true;
}
return false;
}
protected override void OnPaint(PaintEventArgs e)
{
string beginDrawError = "";
if (!Render(ref beginDrawError,ClientRectangle))
{
PaintUsingSystemDrawing(e.Graphics, beginDrawError);
}
}
private string BeginDraw()
{
return BeginDraw(0,0,ClientSize.Width, ClientSize.Height);
}
private string BeginDraw(int _left, int _top, int _width, int _height)
{
return BeginDraw(new System.Drawing.Rectangle(_left, _top, _width, _height));
}
private string BeginDraw(int _width, int _height)
{
return BeginDraw(0,0,_width, _height);
}
private string BeginDraw(System.Drawing.Rectangle _rect)
{
if (graphicsDeviceService == null)
{
return Text + "\n\n" + GetType();
}
string deviceResetError = HandleDeviceReset();
if (!string.IsNullOrEmpty(deviceResetError))
{
return deviceResetError;
}
Viewport viewport = new Viewport();
viewport.X = _rect.Left;
viewport.Y = _rect.Top;
viewport.Width = _rect.Width;
viewport.Height = _rect.Height;
viewport.MinDepth = 0;
viewport.MaxDepth = 1;
GraphicsDevice.Viewport = viewport;
return null;
}
private void EndDraw()
{
try
{
Rectangle sourceRectangle = new Rectangle(0, 0, ClientSize.Width,
ClientSize.Height);
GraphicsDevice.Present(sourceRectangle, null, this.Handle);
}
catch
{
}
}
private string HandleDeviceReset()
{
bool deviceNeedsReset = false;
switch (GraphicsDevice.GraphicsDeviceStatus)
{
case GraphicsDeviceStatus.Lost:
return "Graphics device lost";
case GraphicsDeviceStatus.NotReset:
deviceNeedsReset = true;
break;
default:
PresentationParameters pp = GraphicsDevice.PresentationParameters;
deviceNeedsReset = (ClientSize.Width > pp.BackBufferWidth) ||
(ClientSize.Height > pp.BackBufferHeight);
break;
}
if (deviceNeedsReset)
{
try
{
graphicsDeviceService.ResetDevice(ClientSize.Width,
ClientSize.Height);
}
catch (Exception e)
{
return "Graphics device reset failed\n\n" + e;
}
}
return null;
}
protected virtual void PaintUsingSystemDrawing(Graphics graphics, string text)
{
graphics.Clear(Color.CornflowerBlue);
using (Brush brush = new SolidBrush(Color.Black))
{
using (StringFormat format = new StringFormat())
{
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
graphics.DrawString(text, Font, brush, ClientRectangle, format);
}
}
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
}
#endregion
#region Abstract Methods
protected abstract void Initialize();
protected abstract void Draw();
#endregion
}
}
Inherit Your control from this one.
Override Draw and Initialize Methods.
Enjoy.
Regards,
Maxim.