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


using System; 
using System.Collections; 
using System.Drawing; 
using System.Threading; 
using Microsoft.DirectX; 
using Microsoft.DirectX.Direct3D; 
 
namespace GameEngine 
{ 
	///  
	/// Summary description for Model. 
	///  
	public class Cloth : Object3D, IDynamic 
	{ 
		private struct Node 
		{ 
			public float  mass; 
			public float  inverse_mass; 
			public Vector3 position; 
			public Vector3 velocity; 
			public Vector3 acceleration; 
			public Vector3 force; 
			public bool    constrained; 
 
			public Node(float mass_, double x, double y, double z, bool fixed_in_place) 
			{ 
				mass = mass_; 
				inverse_mass = 1.0f / mass; 
				position.X = (float)x; 
				position.Y = (float)y; 
				position.Z = (float)z; 
				velocity.X = 0.0f; 
				velocity.Y = 0.0f; 
				velocity.Z = 0.0f; 
				acceleration.X = 0.0f; 
				acceleration.Y = 0.0f; 
				acceleration.Z = 0.0f; 
				force.X = 0.0f; 
				force.Y = 0.0f; 
				force.Z = 0.0f; 
				constrained = fixed_in_place; 
			} 
		} 
 
		private struct NodeIndex 
		{ 
			public int row; 
			public int column; 
		} 
 
		private struct Spring 
		{ 
			public NodeIndex node1; 
			public NodeIndex node2; 
			public float	 spring_constant; 
			public float     damping; 
			public float     length; 
		} 
 
		#region Attributes 
		private CustomVertex.PositionNormalTextured[]  m_vertices;    
		private VertexBuffer m_VB = null;  // Vertex buffer 
		private IndexBuffer  m_IB = null;  // Index buffer 
		//indices buffer 
		private short[] indices; 
		private Texture      m_Texture; // image for face 
		private Node[,] nodes; 
		private int num_springs; 
		private int num_faces; 
		private int num_rows; 
		private int num_columns; 
		private int num_nodes; 
		private Spring[] springs; 
		private Vector3  m_vOffset = new Vector3(0.0f, 0.0f, 0.0f); 
		private Attitude m_AttitudeOffset = new Attitude(); 
		private bool m_bValid = false; 
		private Thread        m_physics_thread; 
		private bool thread_active = true; 
		private Mutex mutex = new Mutex(); 
 
		// global variables 
		private static Vector3 wind = new Vector3(); 
 
		// constants 
		private static float gravity = -32.174f;  
		private static float spring_tension = 50.10f; 
		private static float damping = 1.70f; 
		private static float drag_coefficient = 0.01f; 
		#endregion 
 
		#region Properties 
		public Vector3 Offset { set { m_vOffset = value; } get { return m_vOffset; } } 
 
		public static float EastWind { set { wind.X = value; } get { return wind.X; } } 
		public static float NorthWind { set { wind.Z = value; } get { return wind.Z; } } 
		#endregion 
 
 
		public Cloth(string name, string texture_name, int rows, int columns, double spacing, float mass) : base(name) 
		{ 
			try  
			{ 
				num_rows = rows; 
				num_columns = columns; 
				m_Texture = GraphicsUtility.CreateTexture(CGameEngine.Device3D, texture_name);  
				nodes = new Node[rows+1,columns+1]; 
				num_faces = rows * columns * 2; 
				num_springs = columns * ( rows+1) + rows * (columns+1) + columns*rows*2; 
				springs = new Spring[num_springs]; 
 
				wind.X = 0.0f; 
				wind.Y = 0.0f; 
				wind.Z = 0.0f; 
 
				num_nodes = (rows+1) * (columns+1); 
 
				m_vertices = new CustomVertex.PositionNormalTextured[num_nodes]; 
 
				float mass_per_node = mass / num_nodes; 
 
				for ( int r=0; r<=rows; r++ ) 
				{ 
					for ( int c=0; c <=columns; c++ ) 
					{ 
						nodes[r,c] = new Node(mass_per_node, -(c*spacing), -(r*spacing), 0.0, c==0 && (r==0 || r == rows)); 
					} 
				} 
 
				// Create a buffer for rendering the cloth 
				m_VB = new VertexBuffer( typeof(CustomVertex.PositionNormalTextured), num_nodes, 
					CGameEngine.Device3D, Usage.WriteOnly, CustomVertex.PositionNormalTextured.Format, 
					Pool.Default ); 
 
				m_IB = new IndexBuffer(typeof(short), num_faces * 3, CGameEngine.Device3D, Usage.WriteOnly, Pool.Managed); 
				indices = new short[num_faces * 3]; 
				m_IB.Created += new System.EventHandler(this.PopulateIndexBuffer); 
				this.PopulateIndexBuffer(m_IB, null); 
 
				m_VB.Created += new System.EventHandler(this.PopulateBuffer); 
				this.PopulateBuffer(m_VB, null); 
 
				// create the springs 
				int index = 0; 
				for ( int r=0; r<=rows; r++ ) 
				{ 
					for ( int c=0; c <=columns; c++ ) 
					{ 
						if ( c < columns ) 
						{ 
							springs[index].node1.row = r; 
							springs[index].node1.column = c; 
							springs[index].node2.row = r; 
							springs[index].node2.column = c+1; 
							springs[index].spring_constant = spring_tension; 
							springs[index].damping = damping; 
							Vector3 length = nodes[r,c].position - nodes[r,c+1].position; 
							springs[index].length = length.Length(); 
							index++; 
						} 
						if ( r < rows ) 
						{ 
							springs[index].node1.row = r; 
							springs[index].node1.column = c; 
							springs[index].node2.row = r+1; 
							springs[index].node2.column = c; 
							springs[index].spring_constant = spring_tension; 
							springs[index].damping = damping; 
							Vector3 length = nodes[r,c].position - nodes[r+1,c].position; 
							springs[index].length = length.Length(); 
							index++; 
						} 
						if ( r < (rows-1) && c < (columns-1) ) 
						{ 
							springs[index].node1.row = r; 
							springs[index].node1.column = c; 
							springs[index].node2.row = r+1; 
							springs[index].node2.column = c+1; 
							springs[index].spring_constant = spring_tension; 
							springs[index].damping = damping; 
							Vector3 length = nodes[r,c].position - nodes[r+1,c+1].position; 
							springs[index].length = length.Length(); 
							index++; 
						} 
						if ( r < (rows-1) && c > 0 ) 
						{ 
							springs[index].node1.row = r; 
							springs[index].node1.column = c; 
							springs[index].node2.row = r+1; 
							springs[index].node2.column = c-1; 
							springs[index].spring_constant = spring_tension; 
							springs[index].damping = damping; 
							Vector3 length = nodes[r,c].position - nodes[r+1,c-1].position; 
							springs[index].length = length.Length(); 
							index++; 
						} 
					} 
				} 
 
				m_physics_thread = new Thread(new ThreadStart(DoPhysics)); 
				m_physics_thread.Start(); 
				m_bValid = true; 
			} 
			catch (DirectXException d3de) 
			{ 
				Console.AddLine("Unable to create cloth for " + name); 
				Console.AddLine(d3de.ErrorString); 
			} 
			catch ( Exception e ) 
			{ 
				Console.AddLine("Unable to create cloth for " + name); 
				Console.AddLine(e.Message); 
			} 
			 
		} 
 
		public void PopulateBuffer(object sender, EventArgs e) 
		{ 
			VertexBuffer vb = (VertexBuffer)sender; 
 
			int index = 0; 
			for ( int r=0; r<(1+num_rows); r++ ) 
			{ 
				for ( int c=0; c <(1+num_columns); c++ ) 
				{ 
					m_vertices[index].SetPosition(nodes[r,c].position); 
					m_vertices[index].SetNormal(new Vector3(0.0f, 0.0f, 1.0f)); 
					m_vertices[index].Tv = (float)r / (float)(num_rows); 
					m_vertices[index].Tu = (float)c / (float)(num_columns); 
					index++; 
				} 
			} 
			// Copy vertices into vertexbuffer 
			mutex.WaitOne(); 
			vb.SetData(m_vertices, 0, 0); 
			mutex.ReleaseMutex(); 
		} 
 
		public void PopulateIndexBuffer(object sender, EventArgs e) 
		{ 
			int index = 0; 
 
			IndexBuffer g = (IndexBuffer)sender; 
			for ( int r=0; r 0 ) 
				{ 
					Object3D obj; 
					for ( int i=0; i 0 ) 
			{ 
				Object3D obj; 
				for ( int i=0; i