www.pudn.com > IntroductionTo3DGameEngineDesign.rar > D3DUtil.cs


//----------------------------------------------------------------------------- 
// File: D3DUtil.cs 
// 
// Desc: Shortcut functions for using DX objects 
// 
// Copyright (c) Microsoft Corporation. All rights reserved 
//----------------------------------------------------------------------------- 
using System; 
using System.Windows.Forms; 
using System.Drawing; 
using Microsoft.DirectX; 
using Microsoft.DirectX.Direct3D; 
using Direct3D = Microsoft.DirectX.Direct3D; 
 
 
 
 
///  
/// Various helper functions for graphics samples 
///  
public class GraphicsUtility 
{ 
    ///  
    /// Private Constructor  
    ///  
    private GraphicsUtility()  
    {  
    } 
 
 
 
    ///  
    /// Initializes a Material structure, setting the diffuse and ambient 
    /// colors. It does not set emissive or specular colors. 
    ///  
    /// The ambient and diffuse color 
    /// A defined material 
	public static Direct3D.Material InitMaterial(System.Drawing.Color c) 
	{ 
		Material mtrl = new Material(); 
		mtrl.Ambient = mtrl.Diffuse = c; 
		return mtrl; 
	} 
 
 
 
 
    ///  
    /// Initializes a light, setting the light position. The 
    /// diffuse color is set to white; specular and ambient are left as black. 
    ///  
    /// Which light to initialize 
    /// The type 
	public static void InitLight(Light light, LightType ltType, float x, float y, float z) 
	{ 
		light.Type        = ltType; 
		light.Diffuse = System.Drawing.Color.White; 
		light.Position = new Vector3(x,y,z); 
		light.Direction = Vector3.Normalize(light.Position); 
		light.Range        = 1000.0f; 
	} 
 
 
 
 
    ///  
    /// Helper function to create a texture. It checks the root path first, 
    /// then tries the DXSDK media path (as specified in the system registry). 
    ///  
	public static Texture CreateTexture(Device device, string textureFilename, Format format) 
	{ 
		// Get the path to the texture 
		string path = DXUtil.FindMediaFile(null, textureFilename); 
 
		// Create the texture using D3DX 
		return TextureLoader.FromFile(device, path, D3DX.Default, D3DX.Default, D3DX.Default, 0, format,  
			Pool.Managed, Filter.Triangle|Filter.Mirror,  
			Filter.Triangle|Filter.Mirror, 0); 
	} 
 
 
 
 
    ///  
    /// Helper function to create a texture. It checks the root path first, 
    /// then tries the DXSDK media path (as specified in the system registry). 
    ///  
    public static Texture CreateTexture(Device device, string textureFilename) 
	{ 
		return GraphicsUtility.CreateTexture(device, textureFilename, Format.Unknown); 
	} 
 
 
 
 
 
    ///  
    /// Returns a view matrix for rendering to a face of a cubemap. 
    ///  
	public static Matrix GetCubeMapViewMatrix(CubeMapFace face) 
	{ 
		Vector3 vEyePt = new Vector3(0.0f, 0.0f, 0.0f); 
		Vector3 vLookDir = new Vector3(); 
		Vector3 vUpDir = new Vector3(); 
 
		switch (face) 
		{ 
			case CubeMapFace.PositiveX: 
				vLookDir = new Vector3(1.0f, 0.0f, 0.0f); 
				vUpDir   = new Vector3(0.0f, 1.0f, 0.0f); 
				break; 
			case CubeMapFace.NegativeX: 
				vLookDir = new Vector3(-1.0f, 0.0f, 0.0f); 
				vUpDir   = new Vector3(0.0f, 1.0f, 0.0f); 
				break; 
			case CubeMapFace.PositiveY: 
				vLookDir = new Vector3(0.0f, 1.0f, 0.0f); 
				vUpDir   = new Vector3(0.0f, 0.0f,-1.0f); 
				break; 
			case CubeMapFace.NegativeY: 
				vLookDir = new Vector3(0.0f,-1.0f, 0.0f); 
				vUpDir   = new Vector3(0.0f, 0.0f, 1.0f); 
				break; 
			case CubeMapFace.PositiveZ: 
				vLookDir = new Vector3(0.0f, 0.0f, 1.0f); 
				vUpDir   = new Vector3(0.0f, 1.0f, 0.0f); 
				break; 
			case CubeMapFace.NegativeZ: 
				vLookDir = new Vector3(0.0f, 0.0f,-1.0f); 
				vUpDir   = new Vector3(0.0f, 1.0f, 0.0f); 
				break; 
		} 
 
		// Set the view transform for this cubemap surface 
		Matrix matView = Matrix.LookAtLH(vEyePt, vLookDir, vUpDir); 
		return matView; 
	} 
 
 
 
 
    ///  
    /// Returns a quaternion for the rotation implied by the window's cursor position 
    ///  
	public static Quaternion GetRotationFromCursor(System.Windows.Forms.Form control, float fTrackBallRadius) 
	{ 
		System.Drawing.Point pt = System.Windows.Forms.Cursor.Position; 
		System.Drawing.Rectangle rc = control.ClientRectangle; 
		pt = control.PointToClient(pt); 
		float xpos = (((2.0f * pt.X) / (rc.Right-rc.Left)) - 1); 
		float ypos = (((2.0f * pt.Y) / (rc.Bottom-rc.Top)) - 1); 
		float sz; 
 
		if (xpos == 0.0f && ypos == 0.0f) 
			return new Quaternion(0.0f, 0.0f, 0.0f, 1.0f); 
 
		float d2 = (float)Math.Sqrt(xpos*xpos + ypos*ypos); 
 
		if (d2 < fTrackBallRadius * 0.70710678118654752440) // Inside sphere 
			sz = (float)Math.Sqrt(fTrackBallRadius*fTrackBallRadius - d2*d2); 
		else                                                 // On hyperbola 
			sz = (fTrackBallRadius*fTrackBallRadius) / (2.0f*d2); 
 
		// Get two points on trackball's sphere 
		Vector3 p1 = new Vector3(xpos, ypos, sz); 
		Vector3 p2 = new Vector3(0.0f, 0.0f, fTrackBallRadius); 
 
		// Get axis of rotation, which is cross product of p1 and p2 
		Vector3 axis = Vector3.Cross(p1,p2); 
 
		// Calculate angle for the rotation about that axis 
		float t = Vector3.Length(Vector3.Subtract(p2,p1)) / (2.0f*fTrackBallRadius); 
		if (t > +1.0f) t = +1.0f; 
		if (t < -1.0f) t = -1.0f; 
		float fAngle = (float)(2.0f * Math.Asin(t)); 
 
		// Convert axis to quaternion 
		return Quaternion.RotationAxis(axis, fAngle); 
	} 
 
 
 
 
    ///  
    /// Returns a quaternion for the rotation implied by the window's cursor position 
    ///  
	public static Quaternion GetRotationFromCursor(System.Windows.Forms.Form control) 
	{ 
		return GetRotationFromCursor(control, 1.0f); 
	} 
 
 
 
 
    ///  
    /// Axis to axis quaternion double angle (no normalization) 
    /// Takes two points on unit sphere an angle THETA apart, returns 
    /// quaternion that represents a rotation around cross product by 2*THETA. 
    ///  
	public static Quaternion D3DXQuaternionUnitAxisToUnitAxis2(Vector3 fromVector, Vector3 toVector) 
	{ 
		Vector3 axis = Vector3.Cross(fromVector, toVector);    // proportional to sin(theta) 
		return new Quaternion(axis.X, axis.Y, axis.Z, Vector3.Dot(fromVector, toVector)); 
	} 
 
 
 
 
    ///  
    /// Axis to axis quaternion  
    /// Takes two points on unit sphere an angle THETA apart, returns 
    /// quaternion that represents a rotation around cross product by theta. 
    ///  
	public static Quaternion D3DXQuaternionAxisToAxis(Vector3 fromVector, Vector3 toVector) 
	{ 
		Vector3 vA = Vector3.Normalize(fromVector), vB = Vector3.Normalize(toVector); 
		Vector3 vHalf = Vector3.Add(vA,vB); 
		vHalf = Vector3.Normalize(vHalf); 
		return GraphicsUtility.D3DXQuaternionUnitAxisToUnitAxis2(vA, vHalf); 
	} 
 
 
 
     
    ///  
    /// Gets the number of ColorChanelBits from a format 
    ///  
	static public int GetColorChannelBits(Format format) 
	{ 
		switch (format) 
		{ 
			case Format.R8G8B8: 
				return 8; 
			case Format.A8R8G8B8: 
				return 8; 
			case Format.X8R8G8B8: 
				return 8; 
			case Format.R5G6B5: 
				return 5; 
			case Format.X1R5G5B5: 
				return 5; 
			case Format.A1R5G5B5: 
				return 5; 
			case Format.A4R4G4B4: 
				return 4; 
			case Format.R3G3B2: 
				return 2; 
			case Format.A8R3G3B2: 
				return 2; 
			case Format.X4R4G4B4: 
				return 4; 
			case Format.A2B10G10R10: 
				return 10; 
			case Format.A2R10G10B10: 
				return 10; 
			default: 
				return 0; 
		} 
	} 
 
 
 
 
    ///  
    /// Gets the number of alpha channel bits  
    ///  
	static public int GetAlphaChannelBits(Format format) 
	{ 
		switch (format) 
		{ 
			case Format.R8G8B8: 
				return 0; 
			case Format.A8R8G8B8: 
				return 8; 
			case Format.X8R8G8B8: 
				return 0; 
			case Format.R5G6B5: 
				return 0; 
			case Format.X1R5G5B5: 
				return 0; 
			case Format.A1R5G5B5: 
				return 1; 
			case Format.A4R4G4B4: 
				return 4; 
			case Format.R3G3B2: 
				return 0; 
			case Format.A8R3G3B2: 
				return 8; 
			case Format.X4R4G4B4: 
				return 0; 
			case Format.A2B10G10R10: 
				return 2; 
			case Format.A2R10G10B10: 
				return 2; 
			default: 
				return 0; 
		} 
	} 
 
 
 
     
    ///  
    /// Gets the number of depth bits 
    ///  
	static public int GetDepthBits(DepthFormat format) 
	{ 
		switch (format) 
		{ 
			case DepthFormat.D16: 
				return 16; 
			case DepthFormat.D15S1: 
				return 15; 
			case DepthFormat.D24X8: 
				return 24; 
			case DepthFormat.D24S8: 
				return 24; 
			case DepthFormat.D24X4S4: 
				return 24; 
			case DepthFormat.D32: 
				return 32; 
			default: 
				return 0; 
		} 
	} 
 
 
 
 
    ///  
    /// Gets the number of stencil bits 
    ///  
	static public int GetStencilBits(DepthFormat format) 
	{ 
		switch (format) 
		{ 
			case DepthFormat.D16: 
				return 0; 
			case DepthFormat.D15S1: 
				return 1; 
			case DepthFormat.D24X8: 
				return 0; 
			case DepthFormat.D24S8: 
				return 8; 
			case DepthFormat.D24X4S4: 
				return 4; 
			case DepthFormat.D32: 
				return 0; 
			default: 
				return 0; 
		} 
	} 
 
 
 
 
    ///  
    /// Assembles and creates a file-based vertex shader 
    ///  
	public static VertexShader CreateVertexShader(Device device, string filename) 
	{ 
		GraphicsStream code = null; 
		string path = null; 
	 
		// Get the path to the vertex shader file 
		path = DXUtil.FindMediaFile(null, filename); 
 
		// Assemble the vertex shader file 
		code = ShaderLoader.FromFile(path, null, 0); 
 
		// Create the vertex shader 
		return new VertexShader(device, code); 
	} 
 
} 
 
 
 
 
///  
/// An arc ball class 
///  
public class GraphicsArcBall 
{ 
	private int internalWidth;   // ArcBall's window width 
	private int internalHeight;  // ArcBall's window height 
	private float internalradius;  // ArcBall's radius in screen coords 
	private float internalradiusTranslation; // ArcBall's radius for translating the target 
 
	private Quaternion internaldownQuat;               // Quaternion before button down 
	private Quaternion internalnowQuat;                // Composite quaternion for current drag 
	private Matrix internalrotationMatrix;         // Matrix for arcball's orientation 
	private Matrix internalrotationDelta;    // Matrix for arcball's orientation 
	private Matrix internaltranslationMatrix;      // Matrix for arcball's position 
	private Matrix internaltranslationDelta; // Matrix for arcball's position 
	private bool internaldragging;               // Whether user is dragging arcball 
	private bool internaluseRightHanded;        // Whether to use RH coordinate system 
	private int saveMouseX = 0;      // Saved mouse position 
	private int saveMouseY = 0; 
	private Vector3 internalvectorDown;         // Button down vector 
	System.Windows.Forms.Control parent; // parent 
 
 
 
 
    ///  
    /// Constructor 
    ///  
	public GraphicsArcBall(System.Windows.Forms.Control p) 
	{ 
		internaldownQuat = Quaternion.Identity; 
		internalnowQuat = Quaternion.Identity; 
		internalrotationMatrix = Matrix.Identity; 
		internalrotationDelta = Matrix.Identity; 
		internaltranslationMatrix = Matrix.Identity; 
		internaltranslationDelta  = Matrix.Identity; 
		internaldragging = false; 
		internalradiusTranslation = 1.0f; 
		internaluseRightHanded = false; 
 
		parent = p; 
		// Hook the events  
		p.MouseDown += new MouseEventHandler(this.OnContainerMouseDown); 
		p.MouseUp += new MouseEventHandler(this.OnContainerMouseUp); 
		p.MouseMove += new MouseEventHandler(this.OnContainerMouseMove); 
	} 
 
 
 
 
    ///  
    /// Set the window dimensions 
    ///  
	public void SetWindow(int width, int height, float radius) 
	{ 
		// Set ArcBall info 
		internalWidth  = width; 
		internalHeight = height; 
		internalradius = radius; 
	} 
 
 
 
 
    ///  
    /// Screen coords to a vector 
    ///  
	private Vector3 ScreenToVector(int xpos, int ypos) 
	{ 
		// Scale to screen 
		float x   = -(xpos - internalWidth/2)  / (internalradius*internalWidth/2); 
		float y   =  (ypos - internalHeight/2) / (internalradius*internalHeight/2); 
 
		if (internaluseRightHanded) 
		{ 
			x = -x; 
			y = -y; 
		} 
 
		float z   = 0.0f; 
		float mag = x*x + y*y; 
 
		if (mag > 1.0f) 
		{ 
			float scale = 1.0f/(float)Math.Sqrt(mag); 
			x *= scale; 
			y *= scale; 
		} 
		else 
			z = (float)Math.Sqrt(1.0f - mag); 
 
		// Return vector 
		return new Vector3(x, y, z); 
	} 
 
 
 
 
    ///  
    /// Fired when the containers mouse button is down 
    ///  
	private void OnContainerMouseDown(object sender, System.Windows.Forms.MouseEventArgs e) 
	{ 
		// Store off the position of the cursor when the button is pressed 
		saveMouseX = e.X; 
		saveMouseY = e.Y; 
 
		if (e.Button == System.Windows.Forms.MouseButtons.Left) 
		{ 
			// Start drag mode 
			internaldragging = true; 
			internalvectorDown = ScreenToVector(e.X, e.Y); 
			internaldownQuat = internalnowQuat; 
		} 
	} 
 
 
 
 
    ///  
    /// Fired when the containers mouse button has been released 
    ///  
	private void OnContainerMouseUp(object sender, System.Windows.Forms.MouseEventArgs e) 
	{ 
		if (e.Button == System.Windows.Forms.MouseButtons.Left) 
		{ 
			// End drag mode 
			internaldragging = false; 
		} 
	} 
 
 
 
 
    ///  
    /// Fired when the containers mouse is moving 
    ///  
	private void OnContainerMouseMove(object sender, System.Windows.Forms.MouseEventArgs e) 
	{ 
		if (e.Button == System.Windows.Forms.MouseButtons.Left) 
		{ 
			if (internaldragging) 
			{ 
				// recompute nowQuat 
				Vector3 vCur = ScreenToVector(e.X, e.Y); 
				Quaternion qAxisToAxis = GraphicsUtility.D3DXQuaternionAxisToAxis(internalvectorDown, vCur); 
				internalnowQuat = internaldownQuat; 
				internalnowQuat = Quaternion.Multiply(internalnowQuat,qAxisToAxis); 
				internalrotationDelta = Matrix.RotationQuaternion(qAxisToAxis); 
			} 
			else 
				internalrotationDelta = Matrix.Identity; 
 
			internalrotationMatrix = Matrix.RotationQuaternion(internalnowQuat); 
			internaldragging = true; 
		} 
 
		if ((e.Button == System.Windows.Forms.MouseButtons.Right) || (e.Button == System.Windows.Forms.MouseButtons.Middle)) 
		{ 
			// Normalize based on size of window and bounding sphere radius 
			float fDeltaX = (saveMouseX-e.X) * internalradiusTranslation / internalWidth; 
			float fDeltaY = (saveMouseY-e.Y) * internalradiusTranslation / internalHeight; 
 
			if (e.Button == System.Windows.Forms.MouseButtons.Right) 
			{ 
				internaltranslationDelta = Matrix.Translation(-2 * fDeltaX, 2 * fDeltaY, 0.0f); 
				internaltranslationMatrix = Matrix.Multiply(internaltranslationMatrix, internaltranslationDelta); 
			} 
			if (e.Button == System.Windows.Forms.MouseButtons.Middle) 
			{ 
				internaltranslationDelta = Matrix.Translation(0.0f, 0.0f, 5 * fDeltaY); 
				internaltranslationMatrix = Matrix.Multiply(internaltranslationMatrix, internaltranslationDelta); 
			} 
 
			// Store mouse coordinate 
			saveMouseX = e.X; 
			saveMouseY = e.Y; 
		} 
	} 
 
	#region Various properties of the class 
	public float Radius 
	{ 
		set 
		{ internalradiusTranslation = value; } 
	} 
	public bool RightHanded 
	{ 
		get { return internaluseRightHanded; } 
		set { internaluseRightHanded = value; } 
	} 
	public Matrix RotationMatrix 
	{ 
		get { return internalrotationMatrix; } 
	} 
	public Matrix RotationDeltaMatrix 
	{ 
		get { return internalrotationDelta; } 
	} 
	public Matrix TranslationMatrix 
	{ 
		get { return internaltranslationMatrix; } 
	} 
	public Matrix TranslationDeltaMatrix 
	{ 
		get { return internaltranslationDelta; } 
	} 
	public bool IsBeingDragged 
	{ 
		get { return internaldragging; } 
	} 
	#endregion 
} 
 
 
 
 
///  
/// Handles our meshes 
///  
public class GraphicsMesh : IDisposable 
{ 
	private string fileName = null; 
	private Mesh systemMemoryMesh = null; // SysMem mesh, lives through resize 
	private Mesh localMemoryMesh = null; // Local mesh, rebuilt on resize 
	private Direct3D.Material[] materials = null; 
	private Texture[] textures = null; 
	private bool isUsingMeshMaterials = true; 
	private VertexBuffer systemMemoryVertexBuffer = null; 
	private VertexBuffer localMemoryVertexBuffer = null; 
	private IndexBuffer systemMemoryIndexBuffer = null; 
	private IndexBuffer localMemoryIndexBuffer = null; 
 
 
 
 
    ///  
    /// Constructor 
    ///  
    /// The initial filename 
	public GraphicsMesh(string filename) 
	{ 
		fileName = filename; 
	} 
    public GraphicsMesh() : this ("CD3DFile_Mesh") {} 
 
 
 
 
    ///  
    /// The system memory mesh 
    ///  
	public Mesh SystemMesh 
	{ 
		get { return systemMemoryMesh; } 
	} 
 
 
 
 
    ///  
    /// The local memory mesh 
    ///  
	public Mesh LocalMesh 
	{ 
		get { return localMemoryMesh; } 
	} 
 
 
 
 
    ///  
    /// Should we use the mesh materials 
    ///  
	public bool IsUsingMaterials 
	{ 
		set { isUsingMeshMaterials = value; } 
	} 
 
 
 
 
    ///  
    /// Creates a new mesh 
    ///  
    /// The device used to create the mesh 
    /// the file to load 
	public void Create(Device device, string filename) 
	{ 
		string strPath = null; 
		GraphicsStream adjacencyBuffer; 
		ExtendedMaterial[] Mat; 
 
		if (device != null) 
		{ 
			device.DeviceLost += new System.EventHandler(this.InvalidateDeviceObjects); 
			device.Disposing += new System.EventHandler(this.InvalidateDeviceObjects); 
			device.DeviceReset += new System.EventHandler(this.RestoreDeviceObjects); 
		} 
 
		// Find the path for the file, and convert it to ANSI (for the D3DX API) 
		strPath = DXUtil.FindMediaFile(null, filename); 
 
		// Load the mesh 
		systemMemoryMesh =  Mesh.FromFile(strPath, MeshFlags.SystemMemory, device, out adjacencyBuffer, out Mat); 
 
		// Optimize the mesh for performance 
		systemMemoryMesh.OptimizeInPlace(MeshFlags.OptimizeCompact | MeshFlags.OptimizeAttrSort | MeshFlags.OptimizeVertexCache, adjacencyBuffer); 
 
		textures = new Texture[Mat.Length]; 
		materials = new Direct3D.Material[Mat.Length]; 
 
		for (int i=0; i 
    /// Set the flexible vertex format 
    ///  
	public void SetVertexFormat(Device device, VertexFormats format) 
	{ 
		Mesh pTempSysMemMesh = null; 
		Mesh pTempLocalMesh  = null; 
 
		if (systemMemoryMesh != null) 
		{ 
			pTempSysMemMesh = systemMemoryMesh.Clone(MeshFlags.SystemMemory, format, device); 
		} 
		if (localMemoryMesh != null) 
		{ 
			try 
			{ 
				pTempLocalMesh = localMemoryMesh.Clone(0, format, device); 
			} 
			catch (Exception e) 
			{ 
				pTempSysMemMesh.Dispose(); 
				pTempSysMemMesh = null; 
				throw e; 
			} 
		} 
 
		if (systemMemoryMesh != null) 
			systemMemoryMesh.Dispose(); 
		systemMemoryMesh = null; 
 
		if (localMemoryMesh != null) 
			localMemoryMesh.Dispose(); 
		localMemoryMesh = null; 
 
		// Clean up any vertex/index buffers 
		DisposeLocalBuffers(true, true); 
 
		if (pTempSysMemMesh != null) systemMemoryMesh = pTempSysMemMesh; 
		if (pTempLocalMesh != null) localMemoryMesh  = pTempLocalMesh; 
 
		// Compute normals in case the meshes have them 
		if (systemMemoryMesh != null) 
			systemMemoryMesh.ComputeNormals(); 
		if (localMemoryMesh != null) 
			localMemoryMesh.ComputeNormals(); 
	} 
 
 
 
 
    ///  
    /// Restore the device objects after the device was reset 
    ///  
	public void RestoreDeviceObjects(object sender, EventArgs e) 
	{ 
		if (null == systemMemoryMesh) 
			throw new ArgumentException(); 
 
		Device device = (Device)sender; 
		// Make a local memory version of the mesh. Note: because we are passing in 
		// no flags, the default behavior is to clone into local memory. 
		localMemoryMesh = systemMemoryMesh.Clone(0, systemMemoryMesh.VertexFormat, device); 
		// Clean up any vertex/index buffers 
		DisposeLocalBuffers(false, true); 
 
	} 
 
 
 
 
    ///  
    /// Invalidate our local mesh 
    ///  
	public void InvalidateDeviceObjects(object sender, EventArgs e) 
	{ 
		if (localMemoryMesh != null) 
			localMemoryMesh.Dispose(); 
		localMemoryMesh = null; 
		// Clean up any vertex/index buffers 
		DisposeLocalBuffers(false, true); 
	} 
 
 
 
 
    ///  
    /// Get the vertex buffer assigned to the system mesh 
    ///  
	public VertexBuffer SystemVertexBuffer 
	{ 
		get 
		{ 
			if (systemMemoryVertexBuffer != null) 
				return systemMemoryVertexBuffer; 
 
			if (systemMemoryMesh == null) 
				return null; 
			 
			systemMemoryVertexBuffer = systemMemoryMesh.VertexBuffer; 
			return systemMemoryVertexBuffer; 
		} 
	} 
 
 
 
 
    ///  
    /// Get the vertex buffer assigned to the Local mesh 
    ///  
	public VertexBuffer LocalVertexBuffer 
	{ 
		get 
		{ 
			if (localMemoryVertexBuffer != null) 
				return localMemoryVertexBuffer; 
 
			if (localMemoryMesh == null) 
				return null; 
			 
			localMemoryVertexBuffer = localMemoryMesh.VertexBuffer; 
			return localMemoryVertexBuffer; 
		} 
	} 
 
 
 
 
    ///  
    /// Get the Index buffer assigned to the system mesh 
    ///  
	public IndexBuffer SystemIndexBuffer 
	{ 
		get 
		{ 
			if (systemMemoryIndexBuffer != null) 
				return systemMemoryIndexBuffer; 
 
			if (systemMemoryMesh == null) 
				return null; 
 
			systemMemoryIndexBuffer = systemMemoryMesh.IndexBuffer; 
			return systemMemoryIndexBuffer; 
		} 
	} 
 
 
 
 
    ///  
    /// Get the Index buffer assigned to the Local mesh 
    ///  
	public IndexBuffer LocalIndexBuffer 
	{ 
		get 
		{ 
			if (localMemoryIndexBuffer != null) 
				return localMemoryIndexBuffer; 
 
			if (localMemoryMesh == null) 
				return null; 
 
			localMemoryIndexBuffer = localMemoryMesh.IndexBuffer; 
			return localMemoryIndexBuffer; 
		} 
	} 
 
 
 
 
    ///  
    /// Clean up any resources 
    ///  
	public void Dispose() 
	{ 
		if (textures != null) 
		{ 
			for (int i = 0; i 
    /// Actually draw the mesh 
    ///  
    /// The device used to draw 
    /// Can draw the opaque parts of the mesh 
    /// Can draw the alpha parts of the mesh 
	public void Render(Device device, bool canDrawOpaque, bool canDrawAlpha) 
	{ 
		if (null == localMemoryMesh) 
			throw new ArgumentException(); 
 
		RenderStates rs = device.RenderState; 
		// Frist, draw the subsets without alpha 
		if (canDrawOpaque) 
		{ 
			for (int i=0; i 
    /// Draw the mesh with opaque and alpha  
    ///  
    public void Render(Device device) 
	{ 
		Render(device, true, true); 
	} 
 
 
 
 
    ///  
    /// Cleans up the local vertex buffers/index buffers 
    ///  
    ///  
    ///  
	private void DisposeLocalBuffers(bool systemBuffers, bool localBuffers) 
	{ 
		if (systemBuffers) 
		{ 
			if (systemMemoryIndexBuffer != null) 
				systemMemoryIndexBuffer.Dispose(); 
			systemMemoryIndexBuffer = null; 
 
			if (systemMemoryVertexBuffer != null) 
				systemMemoryVertexBuffer.Dispose(); 
			systemMemoryVertexBuffer = null; 
		} 
		if (localBuffers) 
		{ 
			if (localMemoryIndexBuffer != null) 
				localMemoryIndexBuffer.Dispose(); 
			localMemoryIndexBuffer = null; 
 
			if (localMemoryVertexBuffer != null) 
				localMemoryVertexBuffer.Dispose(); 
			localMemoryVertexBuffer = null; 
		} 
	} 
} 
 
 
 
 
///  
/// D3DX's font class 
///  
public class D3DXFont : IDisposable 
{ 
	protected System.Drawing.Font systemFont; 
	private Direct3D.Font drawingFont = null; 
 
 
 
 
    ///  
    /// Create a new font object 
    ///  
	public D3DXFont(System.Drawing.Font f) 
	{ 
		systemFont = f; 
	} 
 
 
 
 
    ///  
    /// Create a new font object 
    ///  
    /// Name of the font 
    /// The style of the font 
    /// Size of the font 
	public D3DXFont(string fontName, FontStyle style, int size) 
	{ 
		systemFont = new System.Drawing.Font(fontName,size, style); 
	} 
    public D3DXFont(string fontName): this(fontName, FontStyle.Regular, 12) {} 
    public D3DXFont(string fontName, FontStyle style): this(fontName, style, 12) {} 
 
 
 
 
    ///  
    /// Initialize the device objects 
    ///  
	public void InitializeDeviceObjects(Device device) 
	{ 
		drawingFont = new Direct3D.Font(device, systemFont); 
	} 
 
 
 
 
    ///  
    /// Call Begin on our font object 
    ///  
	public void BeginText() 
	{ 
		if (drawingFont == null) 
			return; 
		drawingFont.Begin(); 
	} 
 
 
 
 
    ///  
    /// Draw some text on the screen 
    ///  
	public void DrawText(int x, int y, int color, string text) 
	{ 
		if (drawingFont == null) 
			return; 
 
		System.Drawing.Rectangle rcText = new System.Drawing.Rectangle(x,y,0,0); 
		// Start drawing the text 
		drawingFont.DrawText(text, rcText, 0, color); 
	} 
 
 
 
 
    ///  
    /// Call End on our font object 
    ///  
	public void EndText() 
	{ 
		if (drawingFont == null) 
			return; 
		drawingFont.End(); 
	} 
 
 
 
 
    ///  
    /// Cleanup any resources being used 
    ///  
	public void Dispose() 
	{ 
		if (systemFont != null) 
			systemFont.Dispose(); 
		systemFont = null; 
	} 
}