Template for Direct3D enabled WinForm in Visual C# 2005 Express.

I've just installed the Beta 2 of Visual C# 2005 Express and played around with some of the features, this is an awesome release (if I may say so as an Microsoft Employee). What I've been looking into especially is the possibility to create my own templates and snippets and I must say that the XML-intellisense features are truly helpful, or should I say the additional XSD-schemas for snippets as well as templates. These XSD-schemas are located in the %Program Files%\Microsoft Visual Studio 8\Xml\Schemas directory, you should absolutely check them out.

Now to the really cool stuff, the creation of a Direct3D enabled WinForm, or actually a WinForm with an override of WndProc, some initialization code and additional code that I usually start all my demonstration projects with. You can create both item and project templates, this first trial is an item template, but could easily be converted to a project template. An item template consists of two parts, one configuration file with the .vstemplate extension and the additional files that builds the item, maybe a code file or a blank .bmp file, it depends on the type of item you're creating a template for.

The .vstemplate file looks like this:

<

VSTemplate
   Version="2.0.0"
   Type="Item"
   xmlns="http://schemas.microsoft.com/developer/vstemplate/2005"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation=
"http://schemas.microsoft.com/developer/vstemplate/2005">
<TemplateData>
<Name>Direct3D enhanced WinForm</Name>
<Description>A WinForm with a Direct3D Device</Description>
<Icon
         Package="{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}"
         ID="4535" />
<ProjectType>CSharp</ProjectType>
      <SortOrder>20</SortOrder>
<DefaultName>Direct3DForm.cs</DefaultName>
</TemplateData>
<TemplateContent>
<References>
<Reference>
<Assembly>
               System, 
               Version=2.0.0.0,
               Culture=neutral,
               PublicKeyToken=b77a5c561934e089
            </Assembly>
</Reference>
<Reference>
<Assembly>
               System.Drawing,
               Version=2.0.0.0,
               Culture=neutral,
               PublicKeyToken=b03f5f7f11d50a3a
            </Assembly>
</Reference>
<Reference>
<Assembly>
               System.Windows.Forms,
               Version=2.0.0.0,
               Culture=neutral,
               PublicKeyToken=b77a5c561934e089
            </Assembly>
</Reference>
<Reference>
<Assembly>
               Microsoft.DirectX,
               Version=1.0.900.0,
               Culture=neutral,
               PublicKeyToken=31bf3856ad364e35
            </Assembly>
</Reference>
<Reference>
<Assembly>
               Microsoft.DirectX.Direct3D,
               Version=1.0.900.0,
               Culture=neutral,
               PublicKeyToken=31bf3856ad364e35
            </Assembly>
</Reference>
<Reference>
<Assembly>
               Microsoft.DirectX.Direct3DX,
               Version=1.0.900.0,
               Culture=neutral,
               PublicKeyToken=31bf3856ad364e35
            </Assembly>
</Reference>
</References>
<ProjectItem
         SubType="Form"
         ReplaceParameters="true">Direct3DForm.cs
      </ProjectItem>
</TemplateContent>
</VSTemplate>

The code above goes into a file that I've chosen to call Direct3DForm.vstemplate. If you're intersted in the structure of the template-file, start with examining the code in Visual C# 2005 Express, since the mapping of the XML-schema will give you both intellisense as well as nice comments regarding the different elements and attributes, and if that's not enough, you should really check out the article written by Jason Kemp regarding templates in Visual Studio 2005, you can find it here. There's also a nice article which I read this morning and based this post upon written by Paul Kimmel, you can find it here.

The configuration file includes the name and description of the template, as well as references to assemblies that must be added to the project for the the template to be useful. In this example I will also add some references to the Managed DirectX assemblies. There's also an element that points to the corresponding code file that helps with the actual implementation of the template, in this example the associated code file looks like this:

using

System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Direct3D = Microsoft.DirectX.Direct3D;

public class $safeitemrootname$ : Form
{
   private Direct3D.Device d3dDevice = null;

   public $safeitemrootname$()
   {
      this.Width = 800;
      this.Height = 600;
      Cursor.Hide();
   }

   public bool InitializeEngine() {
      try {
         PresentParameters presentParams = new PresentParameters();
         presentParams.Windowed = true;
         presentParams.SwapEffect = SwapEffect.Discard;

         presentParams.EnableAutoDepthStencil = true;
         presentParams.AutoDepthStencilFormat = DepthFormat.D16;

         presentParams.BackBufferFormat = Format.R5G6B5;
         presentParams.BackBufferHeight = this.Height;
         presentParams.BackBufferWidth = this.Width;

         d3dDevice = new Microsoft.DirectX.Direct3D.Device(
            0,
            Direct3D.DeviceType.Hardware,
            this,
            CreateFlags.HardwareVertexProcessing,
            presentParams);

         SetupCamera();
         return true;
      } catch(Exception ex) {
         return false;
      }
   }

   private void SetupCamera() {
      d3dDevice.Transform.View = Matrix.LookAtLH(
         new Vector3(0,3,-5),
         new Vector3(),
         new Vector3(0,1,0));
      d3dDevice.Transform.Projection = Matrix.PerspectiveFovLH(
         (float)Math.PI/4,
         (float)this.Width/this.Height,
         1,
         15000);
      d3dDevice.Transform.World = Matrix.Identity;
  }

   public void Render() {
      d3dDevice.Clear(ClearFlags.Target | ClearFlags.ZBuffer,
      Color.BlueViolet,1,0);
      d3dDevice.BeginScene();

      // Render objects here

      d3dDevice.EndScene();
      d3dDevice.Present();
   }

   public const int WM_PAINT = 0x000F;
   protected override void WndProc(ref Message m) {
      switch (m.Msg){
         case (WM_PAINT):
            Render();
            break;
         default:
            base.WndProc(ref m);
            break;
         }
   }

   public static void Main() {
      try {
         $safeitemrootname$ engine = new $safeitemrootname$();
         if(engine.InitializeEngine())
            Application.Run(engine);
      } catch(Exception ex) {
         System.Diagnostics.Debug.WriteLine(ex.Message);
      }
   }
}

The code above is saved in a file called Direct3DForm.cs which is based on the parameter specified in the .vstemplate file above. I won't bother discussing what the actual code does, but there's one interesting attribute within the code, the $safeitemrootname$ which will be replaced by Visual C# 2005 Express with the name of the class that you give when creating the form.

These both files gets put into an .zip file and that .zip-file gets copied to the %My Documents%\Visual Studio\ItemTemplates\Visual C#\ directory. When Visual C# 2005 Express starts up, it will browse this directory and add the appropriate templates to the corresponding wizard. When that's done, you can create a new C# projects and choose to add a new item, if you examine the My Templates group, your new template should be there. Pretty cool, and helpful, if you ask me.