CODECUBE VENTURES

XNA Control

Well, I kept trying to finish up this little sample of an XNA control, but I need to get back to working on RocketBrawl, so I figure I'll just release the code as is.

The control is simple enough, you just drop it onto your form and it sets up the XNA Graphics Device to let you render to it. The idea here is that the control would be usable for Tool Development. I've implemented a simple control designer so that the control looks nice when you drop it onto the form.

There are a few things you will have to keep in mind if you want to use this code.

  • I'm currently drawing a png of the xna logo in design mode using the control designer. You will have to look through the code and possible remove this part. Either that, or you can just put an XNA.PNG in your project's resources.

  • I'm currently only setting the PresentationParameters that make the thing render on my hardware. It is likely you will have to change these to fit your hardware profile. Incidentally, this is one of the things that I've submitted feedback to the XNA team about. They should provide guidance about how to detect the hardware settings and set presentation parameters accordingly.

  • The control renders whenever the control paints itself. I actually haven't tested this a lot so I'm not sure if that will work for most scenarios. You might have to change things up so that the host form can call the render method. Right now the control exposes a Render event. To allow the host form to do rendering.

There's probably a few more deficiencies in using this control ... anyone that has half a clue about XNA can probably take this and run with it. I'll revisit it again once I'm further along with RocketBrawl ...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

using Microsoft.Xna;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SpriteEditor.Properties;

namespace SpriteEditor
{
[Designer("SpriteEditor.Design.XnaControlDesigner")]
[System.Drawing.ToolboxBitmap("xnatool.bmp")]
[DefaultEvent("Render")]
public partial class XnaControl : UserControl
{
GraphicsDevice _device;
PresentationParameters pp = new PresentationParameters();

public XnaControl()
{
InitializeComponent();
}

#region Public Properties
public event EventHandler Render;
protected void OnRender()
{
EventHandler r = Render;
if (r != null)
{
r(this, EventArgs.Empty);
}
}

[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
public GraphicsDevice Device
{
get { return _device; }
}

[Category(XnaControl.CategoryString)]
[DefaultValue(DepthFormat.Depth16)]
public DepthFormat DepthFormat
{
get { return pp.AutoDepthStencilFormat; }
set { pp.AutoDepthStencilFormat = value; }
}

[Category(XnaControl.CategoryString)]
[DefaultValue(true)]
public bool EnableAutoDepthStencil
{
get {return pp.EnableAutoDepthStencil;}
set {pp.EnableAutoDepthStencil = value;}
}

[Category(XnaControl.CategoryString)]
[DefaultValue(PresentInterval.Immediate)]
public PresentInterval PresentationInterval
{
get {return pp.PresentationInterval;}
set {pp.PresentationInterval = value;}
}
#endregion

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);

pp.AutoDepthStencilFormat = DepthFormat.Depth16;
pp.BackBufferFormat = SurfaceFormat.Bgr32;
pp.BackBufferHeight = this.Height;
pp.BackBufferWidth = this.Width;
pp.EnableAutoDepthStencil = true;
pp.PresentationInterval = PresentInterval.Immediate;

if (!this.DesignMode)
{
this.SetStyle(
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.Opaque, true);

_device = new GraphicsDevice(
GraphicsAdapter.DefaultAdapter,
DeviceType.Hardware,
this.Handle,
CreateOptions.SoftwareVertexProcessing,
pp);

_device.DeviceLost += new EventHandler(device_DeviceLost);
_device.DeviceReset += new EventHandler(device_DeviceReset);
_device.DeviceResetting += new EventHandler(device_DeviceResetting);
}
}

#region Device Management Callbacks
void device_DeviceResetting(object sender, EventArgs e)
{

}

void device_DeviceReset(object sender, EventArgs e)
{

}

void device_DeviceLost(object sender, EventArgs e)
{

}
#endregion

protected override void OnPaint(PaintEventArgs e)
{
if (!this.DesignMode)
{
_device.Clear(Color.CornflowerBlue);

_device.BeginScene();
OnRender();
_device.EndScene();

_device.Present();
}
}

private const string CategoryString = "Presentation Parameters";
}
}
using System;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.ComponentModel.Design;
using SpriteEditor.Properties;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace SpriteEditor.Design
{
class XnaControlDesigner : ControlDesigner
{
private DesignerVerbCollection verbs;

public XnaControlDesigner()
{
verbs = new DesignerVerbCollection(new DesignerVerb[] {
new DesignerVerb("Dock Fill", new EventHandler(OnDockFill))
});
}
public override System.ComponentModel.Design.DesignerVerbCollection Verbs
{
get { return this.verbs; }
}

private void OnDockFill(object sender, EventArgs eevent)
{
XnaControl xna = this.Component as XnaControl;
xna.Dock = DockStyle.Fill;
}

protected override void OnPaintAdornments(PaintEventArgs pe)
{
base.OnPaintAdornments(pe);
XnaControl xna = this.Component as XnaControl;

pe.Graphics.Clear(System.Drawing.Color.White);
pe.Graphics.DrawImageUnscaled(
Resources.XNA,
(xna.ClientRectangle.Width / 2) - (Resources.XNA.Width/2),
(xna.ClientRectangle.Height / 2) - (Resources.XNA.Height/2));
pe.Graphics.DrawRectangle(new System.Drawing.Pen(System.Drawing.Color.Black), xna.ClientRectangle);

DrawDesignTimeBorder(pe.Graphics, xna);
}

public void DrawDesignTimeBorder(Graphics g, Control control)
{
System.Drawing.Rectangle clientRectangle;
System.Drawing.Color bgColor, adjustedBgColor;
System.Drawing.Pen pen;

clientRectangle = control.ClientRectangle;
bgColor = control.BackColor;
if (((double)bgColor.GetBrightness()) >= 0.5)
adjustedBgColor = ControlPaint.Dark(control.BackColor);
else
adjustedBgColor = ControlPaint.Light(control.BackColor);

pen = new Pen(adjustedBgColor);
pen.DashStyle = DashStyle.Dash;

clientRectangle.Width = (clientRectangle.Width - 1);
clientRectangle.Height = (clientRectangle.Height - 1);

g.DrawRectangle(pen, clientRectangle);
pen.Dispose();
}
}
}

Latest post: Digging Up the First Version of CodeCube

See more in the archives