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


using System; 
using System.Drawing; 
using Microsoft.DirectX; 
using Microsoft.DirectX.Direct3D; 
 
namespace GameEngine 
{ 
	public class TerrainQuad : Object3D, IDisposable 
	{ 
		#region Attributes 
		private CustomVertex.PositionNormalTextured[]  m_Corners;    
		private bool         m_bValid = false; 
		public Vector3       m_Face1Normal; 
		public Vector3       m_Face2Normal; 
 
		public bool Valid { get { return m_bValid; } } 
		public Vector3 FaceNormals { get {  
					Vector3 sum = Vector3.Add(m_Face1Normal, m_Face2Normal);  
					sum.Normalize();  
					return sum; } } 
	#endregion 
 
		public TerrainQuad( string sName, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4 ) : base( sName ) 
		{ 
			m_sName = sName; 
 
			// create the vertices for the box 
			m_Corners = new CustomVertex.PositionNormalTextured[6];  
 
			m_Corners[0].X = p3.X;  // nw 
			m_Corners[0].Y = p3.Y; 
			m_Corners[0].Z = p3.Z; 
			m_Corners[0].Tu = 0.0f; 
			m_Corners[0].Tv = 1.0f; 
			m_Corners[1].X = p1.X;  // sw 
			m_Corners[1].Y = p1.Y; 
			m_Corners[1].Z = p1.Z; 
			m_Corners[1].Tu = 0.0f; 
			m_Corners[1].Tv = 0.0f; 
			m_Corners[2].X = p4.X;  // ne 
			m_Corners[2].Y = p4.Y; 
			m_Corners[2].Z = p4.Z; 
			m_Corners[2].Tu = 1.0f; 
			m_Corners[2].Tv = 1.0f; 
			m_Corners[3].X = p2.X;  // ne 
			m_Corners[3].Y = p2.Y; 
			m_Corners[3].Z = p2.Z; 
			m_Corners[3].Tu = 1.0f; 
			m_Corners[3].Tv = 0.0f; 
 
			m_vPosition.X = (p4.X + p3.X) / 2.0f; 
			m_vPosition.Y = (p1.Y + p2.Y + p3.Y + p4.Y) / 4.0f; 
			m_vPosition.Z = (p1.Z + p3.Z) / 2.0f; 
			double dx = p4.X - p3.X; 
			double dz = p3.Z - p1.Z; 
			m_fRadius = (float)Math.Sqrt( dx * dx + dz * dz ) / 2.0f; 
 
			m_Face1Normal = GameMath.ComputeFaceNormal(  
				new Vector3(m_Corners[0].X,m_Corners[0].Y,m_Corners[0].Z), 
				new Vector3(m_Corners[1].X,m_Corners[1].Y,m_Corners[1].Z), 
				new Vector3(m_Corners[2].X,m_Corners[2].Y,m_Corners[2].Z) ); 
			m_Face2Normal = GameMath.ComputeFaceNormal(  
				new Vector3(m_Corners[1].X,m_Corners[1].Y,m_Corners[1].Z), 
				new Vector3(m_Corners[3].X,m_Corners[3].Y,m_Corners[3].Z), 
				new Vector3(m_Corners[2].X,m_Corners[2].Y,m_Corners[2].Z) ); 
 
			// default the vertex normals to the face normal value just in case 
			m_Corners[0].SetNormal( m_Face1Normal ); 
			m_Corners[1].SetNormal( FaceNormals ); 
			m_Corners[2].SetNormal( FaceNormals ); 
			m_Corners[3].SetNormal( m_Face2Normal ); 
			m_Corners[4].SetNormal( FaceNormals ); 
			m_Corners[5].SetNormal( FaceNormals ); 
 
			m_Corners[4].X = m_Corners[2].X; 
			m_Corners[4].Y = m_Corners[2].Y; 
			m_Corners[4].Z = m_Corners[2].Z; 
			m_Corners[4].Tu = m_Corners[2].Tu; 
			m_Corners[4].Tv = m_Corners[2].Tv; 
			m_Corners[5].X = m_Corners[1].X; 
			m_Corners[5].Y = m_Corners[1].Y; 
			m_Corners[5].Z = m_Corners[1].Z; 
			m_Corners[5].Tu = m_Corners[1].Tu; 
			m_Corners[5].Tv = m_Corners[1].Tv; 
 
			m_bValid = true; 
 
		} 
 
		public void SetCornerNormal( int Corner, Vector3 Normal ) 
		{ 
			Normal.Normalize(); 
			m_Corners[Corner].SetNormal( Normal ); 
		} 
 
		public override void Dispose() 
		{ 
		} 
 
		public int RenderQuad( int Offset, CustomVertex.PositionNormalTextured[] vertices ) 
		{ 
			int newOffset = Offset; 
 
			if ( Valid && !IsCulled ) 
			{ 
				for ( int i=0; i<6; i++ ) 
				{ 
					vertices[Offset+i] = m_Corners[i]; 
				} 
				newOffset += 6; 
				Culled = true; 
			} 
			return newOffset; 
		} 
 
		public override bool InRect( Rectangle rect ) 
		{ 
			bool inside = false; 
 
			// check to see if the object is within this rectangle by checking each corner 
			for ( int i=0; i<4; i++ ) 
			{ 
				if ( rect.Contains((int)m_Corners[i].X,(int)m_Corners[i].Z) ) 
				{ 
					inside = true; 
					break; 
				} 
			} 
			return inside; 
		} 
 
	} 
	///  
	/// Summary description for Terrain. 
	///  
	public class Terrain : IDisposable, ITerrainInfo 
	{ 
 
		private Vector3[,]       m_Elevations; 
		private VertexBuffer m_VB = null;  // Vertex buffer 
		private TerrainQuad[,] m_Quads = null; 
		private int m_xSize; 
		private int m_ySize; 
		private Texture      m_Texture; // image for face 
		private bool m_bValid = false; 
		private CustomVertex.PositionNormalTextured[] m_Vertices; 
		private float m_Spacing; 
 
		public Terrain(int xSize, int ySize, string sName, string sTexture, float fSpacing, float fElevFactor) 
		{ 
			int nTemp; 
 
			m_Elevations = new Vector3[xSize,ySize]; 
			m_xSize = xSize-1; 
			m_ySize = ySize-1; 
			m_Quads = new TerrainQuad[m_xSize,m_ySize]; 
			m_Vertices = new CustomVertex.PositionNormalTextured[3000];  
			m_Spacing = fSpacing; 
 
			try 
			{ 
				System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(sName); 
				for ( int i=0; i 0.0 ) 
				{ 
					attitude.Pitch = (float)(Math.PI/2.0) - attitude.Pitch; 
				} 
				else 
				{ 
					attitude.Pitch = -((float)(Math.PI/2.0) + attitude.Pitch); 
				} 
			} 
			if ( attitude.Pitch > (Math.PI/4.0) || attitude.Pitch < -(Math.PI/4.0) ) 
			{ 
				Console.AddLine("Pitch " + attitude.Pitch*180.0/Math.PI + " " + normal.ToString()); 
			} 
 
			if ( normal.X == 0.0f ) 
			{ 
				attitude.Roll = 0.0f; 
			} 
			else  
			{ 
				attitude.Roll = -(float)Math.Atan(normal.Y/normal.X); 
				if ( attitude.Roll > 0.0 ) 
				{ 
					attitude.Roll = (float)(Math.PI/2.0) - attitude.Roll; 
				} 
				else 
				{ 
					attitude.Roll = -((float)(Math.PI/2.0) + attitude.Roll); 
				} 
			} 
			if ( attitude.Roll > (Math.PI/4.0) || attitude.Roll < -(Math.PI/4.0) ) 
			{ 
				Console.AddLine("Roll " + attitude.Roll*180.0/Math.PI + " " + normal.ToString()); 
			} 
 
 
			attitude.Heading = Heading; 
 
			return attitude; 
		} 
 
		public void Render( Camera cam ) 
		{ 
			int nQuadsDrawn = 0; 
			if ( m_bValid )  
			{ 
				CGameEngine.Device3D.RenderState.CullMode = Cull.Clockwise; 
				CGameEngine.Device3D.VertexFormat = CustomVertex.PositionNormalTextured.Format; 
				Material mtrl = new Material(); 
				mtrl.Ambient = Color.White; 
				mtrl.Diffuse = Color.White; 
				CGameEngine.Device3D.Material = mtrl; 
 
				// Set the texture 
				CGameEngine.Device3D.SetTexture(0, m_Texture ); 
 
				// Set the matrix for normal viewing 
				Matrix matWorld = new Matrix(); 
				matWorld = Matrix.Identity; 
 
				CGameEngine.Device3D.Transform.World = matWorld; 
				CGameEngine.Device3D.Transform.View = cam.View; 
 
				int Offset = 0; 
 
				for ( int i=0; i= 2990 ) 
							{ 
								CGameEngine.Device3D.VertexFormat = CustomVertex.PositionNormalTextured.Format; 
								m_VB.SetData(m_Vertices, 0, 0); 
								CGameEngine.Device3D.SetStreamSource( 0, m_VB, 0 ); 
								CGameEngine.Device3D.DrawPrimitives( PrimitiveType.TriangleList, 0, Offset/3 ); 
								nQuadsDrawn += Offset / 6; 
								Offset = 0; 
							} 
						} 
						catch 
						{ 
							Console.AddLine("Error rendering terrain quad " + i + "," + j); 
						} 
					} 
				} 
				if ( Offset > 0 ) 
				{ 
					try 
					{ 
						CGameEngine.Device3D.VertexFormat = CustomVertex.PositionNormalTextured.Format; 
						m_VB.SetData(m_Vertices, 0, 0); 
						CGameEngine.Device3D.SetStreamSource( 0, m_VB, 0 ); 
						CGameEngine.Device3D.DrawPrimitives( PrimitiveType.TriangleList, 0, Offset/3 ); 
						nQuadsDrawn += Offset / 6; 
						Offset = 0; 
					} 
					catch (DirectXException d3de) 
					{ 
						Console.AddLine("Unable to render terrain " ); 
						Console.AddLine(d3de.ErrorString); 
					} 
					catch ( Exception e ) 
					{ 
						Console.AddLine("Unable to render terrain" ); 
						Console.AddLine(e.Message); 
					} 
 
				} 
			} 
		} 
 
		public void Dispose() 
		{ 
			for ( int i=0; i