// Simple mesh wrapper by Jacob Repp (jacobrepp@gmail.com). The flags are not used // in this version as it was hack/ported from a very old C++ mesh class. Feel free // to tweak for your own needs. using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace GunTest2 { class MeshMaterialGroup { public short[] tris; public Color ambient; public Color diffuse; public Color specular; public IndexBuffer indexBuffer; } class Mesh { Matrix WorldMatrix; public const uint kFlags_TexCoords = 0x1; public const uint kFlags_Color = 0x2; public const uint kFlags_Texturing = 0x4; public VertexBuffer vertexBuffer; public VertexDeclaration vertexDecl; public IndexBuffer indexBuffer; public VertexPositionNormal[] verts; public short[] tris; public uint flags; private List _materialGroups; public Mesh() { WorldMatrix = Matrix.Identity; _materialGroups = new List(); } public void Allocate(uint nVerts, uint nFaces) { verts = new VertexPositionNormal[nVerts]; tris = new short[nFaces * 3]; } public void Enable(uint flags) { this.flags |= flags; } public void Disable(uint flags) { this.flags &= ~flags; } public void AddMaterialGroup(short [] faces, Color ambient, Color diffuse, Color specular) { MeshMaterialGroup matGroup = new MeshMaterialGroup(); matGroup.ambient = ambient; matGroup.diffuse = diffuse; matGroup.specular = specular; // Expand all faces into vertex indexes for submission to the gpu matGroup.tris = new short[faces.Length * 3]; int di = 0; for (int i = 0; i < faces.Length; ++i) { short index = (short)(faces[i] * 3); matGroup.tris[di++] = tris[index + 0]; matGroup.tris[di++] = tris[index + 1]; matGroup.tris[di++] = tris[index + 2]; } _materialGroups.Add(matGroup); } public void SetVertexPosition(uint i, Vector3 pos) { verts[i].Position = pos; } public void SetVertexNormal(uint i, Vector3 norm) { verts[i].Normal = norm; } public void SetFaceIndicies(uint i, ushort a, ushort b, ushort c) { tris[(i * 3) + 0] = (short)a; tris[(i * 3) + 1] = (short)b; tris[(i * 3) + 2] = (short)c; } public void SubmitPrimitives(GraphicsDevice gd, SceneEffect effect) { if(null == vertexBuffer) { // Create the vertex buffer vertexBuffer = new VertexBuffer(gd, verts.Length * VertexPositionNormal.SizeInBytes, ResourceUsage.None, ResourcePool.Managed); vertexBuffer.SetData(verts); vertexDecl = new VertexDeclaration(gd, VertexPositionNormal.VertexElements); if (_materialGroups.Count > 0) { // Create index buffers for each material group foreach (MeshMaterialGroup matGroup in _materialGroups) { if (null != matGroup.indexBuffer) { matGroup.indexBuffer.Dispose(); } matGroup.indexBuffer = new IndexBuffer(gd, 2 * matGroup.tris.Length, ResourceUsage.None, ResourcePool.Managed, IndexElementSize.SixteenBits); matGroup.indexBuffer.SetData(matGroup.tris); } } else { // Create global index buffer indexBuffer = new IndexBuffer(gd, 2 * tris.Length, ResourceUsage.None, ResourcePool.Managed, IndexElementSize.SixteenBits); indexBuffer.SetData(tris); } } gd.VertexDeclaration = vertexDecl; gd.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionNormal.SizeInBytes); // Render the triangles using material groups if they are provided if (_materialGroups.Count > 0) { foreach(MeshMaterialGroup matGroup in _materialGroups) { SceneEffect.State state = new SceneEffect.State(); state.Ambient = matGroup.ambient; state.Diffuse = matGroup.diffuse; state.Specular = matGroup.specular; effect.UpdateEffectState(state); gd.Indices = matGroup.indexBuffer; gd.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, verts.Length, 0, matGroup.tris.Length / 3); } } else { gd.Indices = indexBuffer; gd.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, verts.Length, 0, tris.Length / 3); } } } }