Esempio n. 1
0
		/// <summary>
		/// Creates a plane as a submesh of the given mesh
		/// </summary>
		private static void _createPlane( Mesh mesh )
		{

			SubMesh sub = mesh.CreateSubMesh();
			float[] vertices = new float[ 32 ] {
				-100, -100, 0,	// pos
				0,0,1,			// normal
				0,1,			// texcoord
				100, -100, 0,
				0,0,1,
				1,1,
				100,  100, 0,
				0,0,1,
				1,0,
				-100,  100, 0 ,
				0,0,1,
				0,0
			};

			mesh.SharedVertexData = new VertexData();
			mesh.SharedVertexData.vertexCount = 4;
			VertexDeclaration decl = mesh.SharedVertexData.vertexDeclaration;
			VertexBufferBinding binding = mesh.SharedVertexData.vertexBufferBinding;

			int offset = 0;
			decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Position );
			offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
			decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Normal );
			offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
			decl.AddElement( 0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0 );
			offset += VertexElement.GetTypeSize( VertexElementType.Float2 );

			HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( decl, 4, BufferUsage.StaticWriteOnly );
			binding.SetBinding( 0, vbuf );

			vbuf.WriteData( 0, vbuf.Size, vertices, true );

			sub.useSharedVertices = true;
			HardwareIndexBuffer ibuf = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, 6, BufferUsage.StaticWriteOnly );

			short[] faces = new short[ 6 ] { 0, 1, 2, 0, 2, 3 };
			sub.IndexData.indexBuffer = ibuf;
			sub.IndexData.indexCount = 6;
			sub.IndexData.indexStart = 0;
			ibuf.WriteData( 0, ibuf.Size, faces, true );

			mesh.BoundingBox = new AxisAlignedBox( new Vector3( -100, -100, 0 ), new Vector3( 100, 100, 0 ) );
			mesh.BoundingSphereRadius = Utility.Sqrt( 100 * 100 + 100 * 100 );
		}
Esempio n. 2
0
		private void _loadManual( Mesh mesh, MeshBuildParams mbp )
		{
			SubMesh subMesh = mesh.CreateSubMesh();

			// Set up vertex data
			// Use a single shared buffer
			mesh.SharedVertexData = new VertexData();
			VertexData vertexData = mesh.SharedVertexData;

			// Set up Vertex Declaration
			VertexDeclaration decl = vertexData.vertexDeclaration;
			int currOffset = 0;

			// add position data
			// We always need positions
			decl.AddElement( 0, currOffset, VertexElementType.Float3, VertexElementSemantic.Position );
			currOffset += VertexElement.GetTypeSize( VertexElementType.Float3 );

			// normals are optional
			if ( mbp.Normals )
			{
				decl.AddElement( 0, currOffset, VertexElementType.Float3, VertexElementSemantic.Normal );
				currOffset += VertexElement.GetTypeSize( VertexElementType.Float3 );
			}

			// add texture coords
			for ( ushort i = 0; i < mbp.TexCoordSetCount; i++ )
			{
				decl.AddElement( 0, currOffset, VertexElementType.Float2, VertexElementSemantic.TexCoords, i );
				currOffset += VertexElement.GetTypeSize( VertexElementType.Float2 );
			}

			vertexData.vertexCount = ( mbp.XSegments + 1 ) * ( mbp.YSegments + 1 );

			// create a new vertex buffer (based on current API)
			HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( decl.Clone( 0 ), vertexData.vertexCount, mbp.VertexBufferUsage, mbp.VertexShadowBuffer );

			// get a reference to the vertex buffer binding
			VertexBufferBinding binding = vertexData.vertexBufferBinding;

			// bind the first vertex buffer
			binding.SetBinding( 0, vbuf );

			// transform the plane based on its plane def
			Matrix4 translate = Matrix4.Identity;
			Matrix4 transform = Matrix4.Zero;
			Matrix4 rotation = Matrix4.Identity;
			Matrix3 rot3x3 = Matrix3.Zero;

			Vector3 xAxis, yAxis, zAxis;
			zAxis = mbp.Plane.Normal;
			zAxis.Normalize();
			yAxis = mbp.UpVector;
			yAxis.Normalize();
			xAxis = yAxis.Cross( zAxis );

			if ( xAxis.Length == 0 )
			{
				throw new AxiomException( "The up vector for a plane cannot be parallel to the planes normal." );
			}

			rot3x3.FromAxes( xAxis, yAxis, zAxis );
			rotation = rot3x3;

			// set up transform from origin
			translate.Translation = mbp.Plane.Normal * -mbp.Plane.D;

			transform = translate * rotation;

			float xSpace = mbp.Width / mbp.XSegments;
			float ySpace = mbp.Height / mbp.YSegments;
			float halfWidth = mbp.Width / 2;
			float halfHeight = mbp.Height / 2;
			float xTexCoord = ( 1.0f * mbp.XTile ) / mbp.XSegments;
			float yTexCoord = ( 1.0f * mbp.YTile ) / mbp.YSegments;
			Vector3 vec = Vector3.Zero;
			Vector3 min = Vector3.Zero;
			Vector3 max = Vector3.Zero;
			float maxSquaredLength = 0;
			bool firstTime = true;

			// generate vertex data
			switch ( mbp.Type )
			{
				case MeshBuildType.Plane:
					_generatePlaneVertexData( vbuf, mbp.YSegments, mbp.XSegments, xSpace, halfWidth, ySpace, halfHeight, transform, firstTime, mbp.Normals, rotation, mbp.TexCoordSetCount, xTexCoord, yTexCoord, subMesh, ref min, ref max, ref maxSquaredLength );
					break;
				case MeshBuildType.CurvedPlane:
					_generateCurvedPlaneVertexData( vbuf, mbp.YSegments, mbp.XSegments, xSpace, halfWidth, ySpace, halfHeight, transform, firstTime, mbp.Normals, rotation, mbp.Curvature, mbp.TexCoordSetCount, xTexCoord, yTexCoord, subMesh, ref min, ref max, ref maxSquaredLength );
					break;
				case MeshBuildType.CurvedIllusionPlane:
					_generateCurvedIllusionPlaneVertexData( vbuf, mbp.YSegments, mbp.XSegments, xSpace, halfWidth, ySpace, halfHeight, transform, firstTime, mbp.Normals, mbp.Orientation, mbp.Curvature, xTexCoord, yTexCoord, mbp.TexCoordSetCount, ref min, ref max, ref maxSquaredLength );
					break;
				default:
					throw new Exception( "" );
			}

			// generate face list
			_tesselate2DMesh( subMesh, mbp.XSegments + 1, mbp.YSegments + 1, false, mbp.IndexBufferUsage, mbp.IndexShadowBuffer );

			// generate bounds for the mesh
			mesh.BoundingBox = new AxisAlignedBox( min, max );
			mesh.BoundingSphereRadius = Utility.Sqrt( maxSquaredLength );

		}
        public static Mesh CopyMesh(Mesh mesh)
        {
            Mesh newMesh = new Mesh(mesh.Name);
            if (mesh.Skeleton != null)
                newMesh.NotifySkeleton(mesh.Skeleton);
            newMesh.SetVertexBufferPolicy(mesh.VertexBufferUsage, mesh.UseVertexShadowBuffer);
            newMesh.SetIndexBufferPolicy(mesh.IndexBufferUsage, mesh.UseIndexShadowBuffer);

            // this sets bounding radius as well
            newMesh.BoundingBox = mesh.BoundingBox;

            MeshUtility meshUtility = new MeshUtility();
            for (int i = 0; i < mesh.SubMeshCount; ++i)
                meshUtility.AddSubmeshData(mesh.GetSubMesh(i));

            // This should be done after we finish with the lod stuff
            newMesh.AutoBuildEdgeLists = true;
            newMesh.BuildEdgeList();

            foreach (AttachmentPoint ap in mesh.AttachmentPoints)
                newMesh.AttachmentPoints.Add(new AttachmentPoint(ap));

            for (int i = 0; i < mesh.SubMeshCount; ++i) {
                SubMesh srcSubMesh = mesh.GetSubMesh(i);
                SubMesh dstSubMesh = newMesh.CreateSubMesh(srcSubMesh.Name);
                CopySubMesh(dstSubMesh, srcSubMesh, meshUtility.subMeshDataMap[srcSubMesh.Name]);
            }

            if (mesh.SharedVertexData != null) {
                newMesh.SharedVertexData = new VertexData();
                CopyVertexData(newMesh.SharedVertexData, mesh.SharedVertexData, meshUtility.sharedSubMeshData.VertexIdMap);
                CopyBoneAssignments(newMesh, mesh, meshUtility.sharedSubMeshData.VertexIdMap);
            }
            // newMesh.CompileBoneAssignments();

            return newMesh;
        }
        /// <summary>
        ///    
        /// </summary>
        private void PrepareClonedMesh()
        {
            // create a new mesh based on the original, only with different BufferUsage flags (inside PrepareVertexData)
            clonedMesh = MeshManager.Instance.CreateManual(MESH_NAME);
            clonedMesh.BoundingBox = (AxisAlignedBox)originalMesh.BoundingBox.Clone();
            clonedMesh.BoundingSphereRadius = originalMesh.BoundingSphereRadius;

            // clone the actual data
            clonedMesh.SharedVertexData = PrepareVertexData(originalMesh.SharedVertexData);

            // clone each sub mesh
            for(int i = 0; i < originalMesh.SubMeshCount; i++) {
                SubMesh orgSub = originalMesh.GetSubMesh(i);
                SubMesh newSub = clonedMesh.CreateSubMesh(string.Format("ClonedSubMesh#{0}", i));

                if(orgSub.IsMaterialInitialized) {
                    newSub.MaterialName = orgSub.MaterialName;
                }

                // prepare new vertex data
                newSub.useSharedVertices = orgSub.useSharedVertices;
                newSub.vertexData = PrepareVertexData(orgSub.vertexData);

                // use existing index buffer as is since it wont be modified anyway
                newSub.indexData.indexBuffer = orgSub.indexData.indexBuffer;
                newSub.indexData.indexStart = orgSub.indexData.indexStart;
                newSub.indexData.indexCount = orgSub.indexData.indexCount;
            }
        }
Esempio n. 5
0
		public WaterMesh( String meshName, float planeSize, int cmplx )
		{ // najak R-F
			// Assign Fields to the Initializer values
			this.meshName = meshName;
			this.size = planeSize;
			this.cmplx = cmplx;  // Number of Rows/Columns in the Water Grid representation
			cmplxAdj = (float)System.Math.Pow( ( cmplx / 64f ), 1.4f ) * 2;
			numFaces = 2 * (int)System.Math.Pow( cmplx, 2 );  // Each square is split into 2 triangles.
			numVertices = (int)System.Math.Pow( ( cmplx + 1 ), 2 ); // Vertex grid is (Complexity+1) squared

			// Allocate and initialize space for calculated Normals
			vNorms = new Vector3[ cmplx + 1, cmplx + 1 ]; // vertex Normals for each grid point
			fNorms = new Vector3[ cmplx, cmplx, 2 ]; // face Normals for each triangle

			// Create mesh and submesh to represent the Water
			mesh = (Mesh)MeshManager.Instance.CreateManual( meshName, ResourceGroupManager.DefaultResourceGroupName, null );
			subMesh = mesh.CreateSubMesh();
			subMesh.useSharedVertices = false;

			// Construct metadata to describe the buffers associated with the water submesh
			subMesh.vertexData = new VertexData();
			subMesh.vertexData.vertexStart = 0;
			subMesh.vertexData.vertexCount = numVertices;

			// Define local variables to point to the VertexData Properties
			VertexDeclaration vdecl = subMesh.vertexData.vertexDeclaration;  // najak: seems like metadata
			VertexBufferBinding vbind = subMesh.vertexData.vertexBufferBinding; // najak: pointer to actual buffer

			//najak: Set metadata to describe the three vertex buffers that will be accessed.
			vdecl.AddElement( 0, 0, VertexElementType.Float3, VertexElementSemantic.Position );
			vdecl.AddElement( 1, 0, VertexElementType.Float3, VertexElementSemantic.Normal );
			vdecl.AddElement( 2, 0, VertexElementType.Float2, VertexElementSemantic.TexCoords );

			// Prepare buffer for positions - todo: first attempt, slow
			// Create the Position Vertex Buffer and Bind it index 0 - Write Only
			posVBuf = HwBufMgr.CreateVertexBuffer( vdecl.Clone(0), numVertices, BufferUsage.DynamicWriteOnly );
			vbind.SetBinding( 0, posVBuf );

			// Prepare buffer for normals - write only
			// Create the Normals Buffer and Bind it to index 1 - Write only
			normVBuf = HwBufMgr.CreateVertexBuffer( vdecl.Clone(1), numVertices, BufferUsage.DynamicWriteOnly );
			vbind.SetBinding( 1, normVBuf );

			// Prepare Texture Coordinates buffer (static, written only once)
			// Creates a 2D buffer of 2D coordinates: (Complexity X Complexity), pairs.
			//    Each pair indicates the normalized coordinates of the texture to map to.
			//    (0,1.00), (0.02, 1.00), (0.04, 1.00), ... (1.00,1.00)
			//    (0,0.98), (0.02, 0.98), (0.04, 1.00), ... (1.00,0.98)
			//    ...
			//    (0,0.00), (0.02, 0.00), (0.04, 0.00), ... (1.00,0.00)
			// This construct is simple and is used to calculate the Texture map.
			// Todo: Write directly to the buffer, when Axiom supports this in safe manner
			float[ , , ] tcBufDat = new float[ cmplx + 1, cmplx + 1, 2 ];
			for ( int i = 0; i <= cmplx; i++ )
			{
				// 2D column iterator for texture map
				for ( int j = 0; j <= cmplx; j++ )
				{
					// 2D row iterator for texture map
					// Define the normalized(0..1) X/Y-coordinates for this element of the 2D grid
					tcBufDat[ i, j, 0 ] = (float)i / cmplx;
					tcBufDat[ i, j, 1 ] = 1.0f - ( (float)j / ( cmplx ) );
				}
			}

			// Now Create the actual hardware buffer to contain the Texture Coordinate 2d map.
			//   and Bind it to buffer index 2
			tcVBuf = HwBufMgr.CreateVertexBuffer( vdecl.Clone(2), numVertices, BufferUsage.StaticWriteOnly );
			tcVBuf.WriteData( 0, tcVBuf.Size, tcBufDat, true );
			vbind.SetBinding( 2, tcVBuf );

			// Create a Graphics Buffer on non-shared vertex indices (3 points for each triangle).
			//  Since the water grid consist of [Complexity x Complexity] squares, each square is
			//  split into 2 right triangles 45-90-45.  That is how the water mesh is constructed.
			//  Therefore the number of faces = 2 * Complexity * Complexity
			ushort[ , , ] idxBuf = new ushort[ cmplx, cmplx, 6 ];
			for ( int i = 0; i < cmplx; i++ )
			{ // iterate the rows
				for ( int j = 0; j < cmplx; j++ )
				{ // iterate the columns
					// Define 4 corners of each grid
					ushort p0 = (ushort)( i * ( cmplx + 1 ) + j ); // top left point on square
					ushort p1 = (ushort)( i * ( cmplx + 1 ) + j + 1 ); // top right
					ushort p2 = (ushort)( ( i + 1 ) * ( cmplx + 1 ) + j ); // bottom left
					ushort p3 = (ushort)( ( i + 1 ) * ( cmplx + 1 ) + j + 1 ); // bottom right

					// Split Square Grid element into 2 adjacent triangles.
					idxBuf[ i, j, 0 ] = p2;
					idxBuf[ i, j, 1 ] = p1;
					idxBuf[ i, j, 2 ] = p0; // top-left triangle
					idxBuf[ i, j, 3 ] = p2;
					idxBuf[ i, j, 4 ] = p3;
					idxBuf[ i, j, 5 ] = p1; // bottom-right triangle
				}
			}
			// Copy Index Buffer to the Hardware Index Buffer
			HardwareIndexBuffer hdwrIdxBuf = HwBufMgr.CreateIndexBuffer( IndexType.Size16, 3 * numFaces, BufferUsage.StaticWriteOnly, true );
			hdwrIdxBuf.WriteData( 0, numFaces * 3 * 2, idxBuf, true );

			// Set index buffer for this submesh
			subMesh.indexData.indexBuffer = hdwrIdxBuf;
			subMesh.indexData.indexStart = 0;
			subMesh.indexData.indexCount = 3 * numFaces;

			//Prepare Vertex Position Buffers (Note: make 3, since each frame is function of previous two)
			vBufs = new Vector3[ 3 ][ , ];
			for ( int b = 0; b < 3; b++ )
			{
				vBufs[ b ] = new Vector3[ cmplx + 1, cmplx + 1 ];
				for ( int y = 0; y <= cmplx; y++ )
				{
					for ( int x = 0; x <= cmplx; x++ )
					{
						vBufs[ b ][ y, x ].x = (float)( x ) / (float)( cmplx ) * (float)size;
						vBufs[ b ][ y, x ].y = 0;
						vBufs[ b ][ y, x ].z = (float)( y ) / (float)( cmplx ) * (float)size;
					}
				}
			}

			curBufNum = 0;
			vBuf = vBufs[ curBufNum ];
			posVBuf.WriteData( 0, posVBuf.Size, vBufs[ 0 ], true );

			AxisAlignedBox meshBounds = new AxisAlignedBox( new Vector3( 0, 0, 0 ), new Vector3( size, 0, size ) );
			mesh.BoundingBox = meshBounds;  //	mesh->_setBounds(meshBounds); // najak: can't find _setBounds()

			mesh.Load();
			mesh.Touch();

		} // end WaterMesh Constructor
Esempio n. 6
0
		private static void _createSphere( Mesh mesh )
		{
			// sphere creation code taken from the DeferredShading sample, originally from the [Ogre] wiki
			var pSphereVertex = mesh.CreateSubMesh();

			const int NUM_SEGMENTS = 16;
			const int NUM_RINGS = 16;
			const float SPHERE_RADIUS = 50.0f;

			mesh.SharedVertexData = new VertexData();
			var vertexData = mesh.SharedVertexData;

			// define the vertex format
			var vertexDecl = vertexData.vertexDeclaration;
			var offset = 0;
			// positions
			vertexDecl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Position );
			offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
			// normals
			vertexDecl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Normal );
			offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
			// two dimensional texture coordinates
			vertexDecl.AddElement( 0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0 );
			offset += VertexElement.GetTypeSize( VertexElementType.Float2 );

			// allocate the vertex buffer
			vertexData.vertexCount = ( NUM_RINGS + 1 )*( NUM_SEGMENTS + 1 );

			var vBuf = HardwareBufferManager.Instance.CreateVertexBuffer( vertexDecl.Clone( 0 ), vertexData.vertexCount,
			                                                              BufferUsage.StaticWriteOnly, false );

			var binding = vertexData.vertexBufferBinding;
			binding.SetBinding( 0, vBuf );

			// allocate index buffer
			pSphereVertex.IndexData.indexCount = 6*NUM_RINGS*( NUM_SEGMENTS + 1 );

			pSphereVertex.IndexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16,
			                                                                                        pSphereVertex.IndexData.
			                                                                                        	indexCount,
			                                                                                        BufferUsage.StaticWriteOnly,
			                                                                                        false );
			var iBuf = pSphereVertex.IndexData.indexBuffer;

#if !AXIOM_SAFE_ONLY
			unsafe
#endif
			{
				var iVertex = 0;
				var pVertex = vBuf.Lock( BufferLocking.Discard ).ToFloatPointer();
				var iIndices = 0;
				var pIndices = iBuf.Lock( BufferLocking.Discard ).ToUShortPointer();

				float fDeltaRingAngle = ( Utility.PI/NUM_RINGS );
				float fDeltaSegAngle = ( 2*Utility.PI/NUM_SEGMENTS );
				ushort wVerticeIndex = 0;

				// Generate the group of rings for the sphere
				for ( var ring = 0; ring <= NUM_RINGS; ring++ )
				{
					float r0 = SPHERE_RADIUS*Utility.Sin( ring*fDeltaRingAngle );
					float y0 = SPHERE_RADIUS*Utility.Cos( ring*fDeltaRingAngle );

					// Generate the group of segments for the current ring
					for ( var seg = 0; seg <= NUM_SEGMENTS; seg++ )
					{
						float x0 = r0*Utility.Sin( seg*fDeltaSegAngle );
						float z0 = r0*Utility.Cos( seg*fDeltaSegAngle );

						// Add one vertex to the strip which makes up the sphere
						pVertex[ iVertex++ ] = x0;
						pVertex[ iVertex++ ] = y0;
						pVertex[ iVertex++ ] = z0;

						var vNormal = new Vector3( x0, y0, z0 ).ToNormalized();
						pVertex[ iVertex++ ] = vNormal.x;
						pVertex[ iVertex++ ] = vNormal.y;
						pVertex[ iVertex++ ] = vNormal.z;

						pVertex[ iVertex++ ] = (float)seg/(float)NUM_SEGMENTS;
						pVertex[ iVertex++ ] = (float)ring/(float)NUM_RINGS;

						if ( ring != NUM_RINGS )
						{
							// each vertex (except the last) has six indicies pointing to it
							pIndices[ iIndices++ ] = (ushort)( wVerticeIndex + NUM_SEGMENTS + 1 );
							pIndices[ iIndices++ ] = (ushort)( wVerticeIndex );
							pIndices[ iIndices++ ] = (ushort)( wVerticeIndex + NUM_SEGMENTS );
							pIndices[ iIndices++ ] = (ushort)( wVerticeIndex + NUM_SEGMENTS + 1 );
							pIndices[ iIndices++ ] = (ushort)( wVerticeIndex + 1 );
							pIndices[ iIndices++ ] = (ushort)( wVerticeIndex );
							wVerticeIndex++;
						}
					}
					; // end for seg
				} // end for ring
			}

			// Unlock
			vBuf.Unlock();
			iBuf.Unlock();

			// Generate face list
			pSphereVertex.useSharedVertices = true;

			// the original code was missing this line:
			mesh.BoundingBox = new AxisAlignedBox( new Vector3( -SPHERE_RADIUS, -SPHERE_RADIUS, -SPHERE_RADIUS ),
			                                       new Vector3( SPHERE_RADIUS, SPHERE_RADIUS, SPHERE_RADIUS ) );

			mesh.BoundingSphereRadius = SPHERE_RADIUS;
		}
Esempio n. 7
0
		private static void _createCube( Mesh mesh )
		{
			var sub = mesh.CreateSubMesh();

			const int NUM_VERTICES = 4*6; // 4 vertices per side * 6 sides
			const int NUM_ENTRIES_PER_VERTEX = 8;
			const int NUM_VERTEX_ENTRIES = NUM_VERTICES*NUM_ENTRIES_PER_VERTEX;
			const int NUM_INDICES = 3*2*6; // 3 indices per face * 2 faces per side * 6 sides

			const float CUBE_SIZE = 100.0f;
			const float CUBE_HALF_SIZE = CUBE_SIZE/2.0f;

			// Create 4 vertices per side instead of 6 that are shared for the whole cube.
			// The reason for this is with only 6 vertices the normals will look bad
			// since each vertex can "point" in a different direction depending on the face it is included in.
			var vertices = new float[NUM_VERTEX_ENTRIES]
			               {
			               	// front side
			               	-CUBE_HALF_SIZE, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, // pos
			               	0, 0, 1, // normal
			               	0, 1, // texcoord
			               	CUBE_HALF_SIZE, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, 0, 0, 1, 1, 1, CUBE_HALF_SIZE, CUBE_HALF_SIZE,
			               	CUBE_HALF_SIZE, 0, 0, 1, 1, 0, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, CUBE_HALF_SIZE, 0, 0, 1, 0, 0,
			               	// back side
			               	CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, 0, -1, 0, 1, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE,
			               	-CUBE_HALF_SIZE, 0, 0, -1, 1, 1, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, 0, -1, 1, 0,
			               	CUBE_HALF_SIZE, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, 0, -1, 0, 0, // left side
			               	-CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -1, 0, 0, 0, 1, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE,
			               	CUBE_HALF_SIZE, -1, 0, 0, 1, 1, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, CUBE_HALF_SIZE, -1, 0, 0, 1, 0,
			               	-CUBE_HALF_SIZE, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -1, 0, 0, 0, 0, // right side
			               	CUBE_HALF_SIZE, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, 1, 0, 0, 0, 1, CUBE_HALF_SIZE, -CUBE_HALF_SIZE,
			               	-CUBE_HALF_SIZE, 1, 0, 0, 1, 1, CUBE_HALF_SIZE, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 1, 0, 0, 1, 0,
			               	CUBE_HALF_SIZE, CUBE_HALF_SIZE, CUBE_HALF_SIZE, 1, 0, 0, 0, 0, // up side
			               	-CUBE_HALF_SIZE, CUBE_HALF_SIZE, CUBE_HALF_SIZE, 0, 1, 0, 0, 1, CUBE_HALF_SIZE, CUBE_HALF_SIZE,
			               	CUBE_HALF_SIZE, 0, 1, 0, 1, 1, CUBE_HALF_SIZE, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, 1, 0, 1, 0,
			               	-CUBE_HALF_SIZE, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, 1, 0, 0, 0, // down side
			               	-CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, -1, 0, 0, 1, CUBE_HALF_SIZE, -CUBE_HALF_SIZE,
			               	-CUBE_HALF_SIZE, 0, -1, 0, 1, 1, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, 0, -1, 0, 1, 0,
			               	-CUBE_HALF_SIZE, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, 0, -1, 0, 0, 0
			               };

			mesh.SharedVertexData = new VertexData();
			mesh.SharedVertexData.vertexCount = NUM_VERTICES;
			var decl = mesh.SharedVertexData.vertexDeclaration;
			var bind = mesh.SharedVertexData.vertexBufferBinding;

			var offset = 0;
			decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Position );
			offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
			decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Normal );
			offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
			decl.AddElement( 0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0 );
			offset += VertexElement.GetTypeSize( VertexElementType.Float2 );

			var vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( decl, NUM_VERTICES, BufferUsage.StaticWriteOnly );
			bind.SetBinding( 0, vbuf );

			vbuf.WriteData( 0, vbuf.Size, vertices, true );

			sub.useSharedVertices = true;
			var ibuf = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, NUM_INDICES,
			                                                             BufferUsage.StaticWriteOnly );

			var faces = new short[NUM_INDICES]
			            {
			            	// front
			            	0, 1, 2, 0, 2, 3, // back
			            	4, 5, 6, 4, 6, 7, // left
			            	8, 9, 10, 8, 10, 11, // right
			            	12, 13, 14, 12, 14, 15, // up
			            	16, 17, 18, 16, 18, 19, // down
			            	20, 21, 22, 20, 22, 23
			            };

			sub.IndexData.indexBuffer = ibuf;
			sub.IndexData.indexCount = NUM_INDICES;
			sub.IndexData.indexStart = 0;
			ibuf.WriteData( 0, ibuf.Size, faces, true );

			mesh.BoundingBox = new AxisAlignedBox( new Vector3( -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE ),
			                                       new Vector3( CUBE_HALF_SIZE, CUBE_HALF_SIZE, CUBE_HALF_SIZE ) );

			mesh.BoundingSphereRadius = CUBE_HALF_SIZE;
		}