using System; using System.Collections.Generic; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace SmithGame { public class ModelManager { public enum ModelType { a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, triangle, circle, square, oval, rectangle, sphere, plane, box, custom, Count } public ModelManager() { int count = (int)ModelType.Count; mModels = new SmithModel[count]; for (int i = 0; i < count; ++i) { mModels[i] = new SmithModel(); } sModelManager = this; } public SmithModel[] mModels; private static ModelManager sModelManager = null; public static ModelManager GetModelManager(){return sModelManager;} public SmithModel GetModel(ModelType modelType) { return mModels[(int)modelType]; } public string GetFriendlyModelName(int modelNameIndex) { if (null != mModelNames) { if (null == mFriendlyModelNames) { //Go through and convert all the model names to their friendly version. mFriendlyModelNames = new string[mModelNames.Length]; for (int i = 0; i < mModelNames.Length; ++i) { string modelName = mModelNames[i].ToUpper(); mFriendlyModelNames[i] = modelName; if (modelName[0] == 'N' && modelName.Length > 1) { //This might be a number model (since we can't have raw numbers in the enum). //Check the next character to see if it's a number. If so, fix up the name //by removing the 'n'. if (modelName[1] >= '0' && modelName[1] <= '9') { //We have a number. Get rid of the 'n' off the front. mFriendlyModelNames[i] = modelName.Substring(1); } } } } } return mFriendlyModelNames[modelNameIndex]; } public string[] mModelNames; public string[] mFriendlyModelNames; } public class SmithModel { public SmithModel() { } public void Set(Model model) { mModel = model; // Now setup the bounding shapes for physics stuffs. bool bs_set = false; foreach (ModelMesh mesh in model.Meshes) { if (bs_set) { BoundingSphere temp = mesh.BoundingSphere; BoundingSphere.CreateMerged(ref mBoundingSphere, ref temp, out mBoundingSphere); } else { mBoundingSphere = mesh.BoundingSphere; bs_set = true; } } } public Model mModel; public BoundingSphere mBoundingSphere; } public class CustomModel { public Vector3[] GetPositions() { Vector3[] positions = new Vector3[mVertices.Count]; for (int i = 0; i < positions.Length; i++) { positions[i] = mVertices[i].mPosition; } return positions; } // A vertex type for drawing RoundLines, including an instance index public struct CustomVertex { public Vector3 mPosition; public Vector3 mNormal; public Vector2 mTexutre; public CustomVertex(Vector3 position, Vector3 normal, Vector2 texture) { mPosition = position; mNormal = normal; mTexutre = texture; } public static int SizeInBytes = 8 * sizeof(float); public static VertexElement[] VertexElements = new VertexElement[] { new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0), new VertexElement(0, 12, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0), new VertexElement(0, 24, VertexElementFormat.Vector2, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0) }; } public VertexBuffer mVertexBuffer; public IndexBuffer mIndexBuffer; public VertexDeclaration mVertexDeclaration; public int mBytesPerVertex; public int mNumTriangles; public int mNumVertices; public List mVertices = new List(); public List mIndices = new List(); bool mCreatingMesh = false; public void BeginCreateNewMesh() { GraphicsDevice graphicsDevice = Globals.gGraphicsDevice; mVertexDeclaration = new VertexDeclaration(graphicsDevice, CustomVertex.VertexElements); mBytesPerVertex = CustomVertex.SizeInBytes; mCreatingMesh = true; } /// /// /// /// /// /// /// The index of the vertex added. public int AddVertex(Vector3 position, Vector3 normal, Vector2 texture) { SmithUtils.Verify(mCreatingMesh, "Oops, Must be creating a mesh for this to be called."); mVertices.Add(new CustomVertex(position, normal, texture)); return mVertices.Count -1; } public void AddTriangle(int v0, int v1, int v2) { SmithUtils.Verify(mCreatingMesh, "Oops, Must be creating a mesh for this to be called."); mIndices.Add((short)v0); mIndices.Add((short)v1); mIndices.Add((short)v2); } public void AddQuad(int v0, int v1, int v2, int v3) { SmithUtils.Verify(mCreatingMesh, "Oops, Must be creating a mesh for this to be called."); AddTriangle(v0, v1, v2); AddTriangle(v2, v3, v0); } public void EndCreateNewMesh() { GraphicsDevice graphicsDevice = Globals.gGraphicsDevice; SmithUtils.Verify(mCreatingMesh, "Oops, Must be creating a mesh for this to be called."); mVertexBuffer = new VertexBuffer(graphicsDevice, mBytesPerVertex * mVertices.Count, BufferUsage.WriteOnly); mVertexBuffer.SetData(mVertices.ToArray()); mNumVertices = mVertices.Count; mIndexBuffer = new IndexBuffer(graphicsDevice, sizeof(short) * mIndices.Count, BufferUsage.WriteOnly, IndexElementSize.SixteenBits); mIndexBuffer.SetData(mIndices.ToArray()); mNumTriangles = mIndices.Count / 3; mCreatingMesh = false; } public void SetupForRender() { GraphicsDevice graphicsDevice = Globals.gGraphicsDevice; SmithUtils.Verify(!mCreatingMesh, "Oops, Must NOT be creating a mesh for this to be called."); graphicsDevice.VertexDeclaration = mVertexDeclaration; graphicsDevice.Vertices[0].SetSource(mVertexBuffer, 0, mBytesPerVertex); graphicsDevice.Indices = mIndexBuffer; } public void Draw() { GraphicsDevice graphicsDevice = Globals.gGraphicsDevice; SmithUtils.Verify(!mCreatingMesh, "Oops, Must NOT be creating a mesh for this to be called."); graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, mNumVertices, 0, mNumTriangles); } private static CustomModel sBoxModel; public static CustomModel GetBox() { if (null == sBoxModel) { //Create the box model. sBoxModel = new CustomModel(); sBoxModel.BeginCreateNewMesh(); const float DELTA = 0.5f; int v0, v1, v2, v3; //Front face v0 = sBoxModel.AddVertex(new Vector3(-DELTA, -DELTA, DELTA), new Vector3(0.0f, 0.0f, 1.0f), new Vector2(0.0f, 1.0f)); v1 = sBoxModel.AddVertex(new Vector3(-DELTA, DELTA, DELTA), new Vector3(0.0f, 0.0f, 1.0f), new Vector2(0.0f, 0.0f)); v2 = sBoxModel.AddVertex(new Vector3(DELTA, DELTA, DELTA), new Vector3(0.0f, 0.0f, 1.0f), new Vector2(1.0f, 0.0f)); v3 = sBoxModel.AddVertex(new Vector3(DELTA, -DELTA, DELTA), new Vector3(0.0f, 0.0f, 1.0f), new Vector2(1.0f, 1.0f)); sBoxModel.AddTriangle(v0, v1, v2); sBoxModel.AddTriangle(v2, v3, v0); //Back face v0 = sBoxModel.AddVertex(new Vector3(-DELTA, -DELTA, -DELTA), new Vector3(0.0f, 0.0f, -1.0f), new Vector2(1.0f, 1.0f)); v1 = sBoxModel.AddVertex(new Vector3(-DELTA, DELTA, -DELTA), new Vector3(0.0f, 0.0f, -1.0f), new Vector2(1.0f, 0.0f)); v2 = sBoxModel.AddVertex(new Vector3(DELTA, DELTA, -DELTA), new Vector3(0.0f, 0.0f, -1.0f), new Vector2(0.0f, 0.0f)); v3 = sBoxModel.AddVertex(new Vector3(DELTA, -DELTA, -DELTA), new Vector3(0.0f, 0.0f, -1.0f), new Vector2(0.0f, 1.0f)); sBoxModel.AddTriangle(v0, v2, v1); sBoxModel.AddTriangle(v2, v0, v3); //Right face v0 = sBoxModel.AddVertex(new Vector3(DELTA, -DELTA, -DELTA), new Vector3(1.0f, 0.0f, 0.0f), new Vector2(0.0f, 1.0f)); v1 = sBoxModel.AddVertex(new Vector3(DELTA, DELTA, -DELTA), new Vector3(1.0f, 0.0f, 0.0f), new Vector2(0.0f, 0.0f)); v2 = sBoxModel.AddVertex(new Vector3(DELTA, DELTA, DELTA), new Vector3(1.0f, 0.0f, 0.0f), new Vector2(1.0f, 0.0f)); v3 = sBoxModel.AddVertex(new Vector3(DELTA, -DELTA, DELTA), new Vector3(1.0f, 0.0f, 0.0f), new Vector2(1.0f, 1.0f)); sBoxModel.AddTriangle(v0, v2, v1); sBoxModel.AddTriangle(v2, v0, v3); //Left face v0 = sBoxModel.AddVertex(new Vector3(-DELTA, -DELTA, -DELTA), new Vector3(-1.0f, 0.0f, 0.0f), new Vector2(0.0f, 1.0f)); v1 = sBoxModel.AddVertex(new Vector3(-DELTA, DELTA, -DELTA), new Vector3(-1.0f, 0.0f, 0.0f), new Vector2(0.0f, 0.0f)); v2 = sBoxModel.AddVertex(new Vector3(-DELTA, DELTA, DELTA), new Vector3(-1.0f, 0.0f, 0.0f), new Vector2(1.0f, 0.0f)); v3 = sBoxModel.AddVertex(new Vector3(-DELTA, -DELTA, DELTA), new Vector3(-1.0f, 0.0f, 0.0f), new Vector2(1.0f, 1.0f)); sBoxModel.AddTriangle(v0, v1, v2); sBoxModel.AddTriangle(v2, v3, v0); //Top face v0 = sBoxModel.AddVertex(new Vector3(-DELTA, DELTA, -DELTA), new Vector3(0.0f, 1.0f, 0.0f), new Vector2(0.0f, 1.0f)); v1 = sBoxModel.AddVertex(new Vector3(-DELTA, DELTA, DELTA), new Vector3(0.0f, 1.0f, 0.0f), new Vector2(0.0f, 0.0f)); v2 = sBoxModel.AddVertex(new Vector3(DELTA, DELTA, DELTA), new Vector3(0.0f, 1.0f, 0.0f), new Vector2(1.0f, 0.0f)); v3 = sBoxModel.AddVertex(new Vector3(DELTA, DELTA, -DELTA), new Vector3(0.0f, 1.0f, 0.0f), new Vector2(1.0f, 1.0f)); sBoxModel.AddTriangle(v0, v2, v1); sBoxModel.AddTriangle(v2, v0, v3); //Bottom face v0 = sBoxModel.AddVertex(new Vector3(-DELTA, -DELTA, -DELTA), new Vector3(0.0f, -1.0f, 0.0f), new Vector2(0.0f, 1.0f)); v1 = sBoxModel.AddVertex(new Vector3(-DELTA, -DELTA, DELTA), new Vector3(0.0f, -1.0f, 0.0f), new Vector2(0.0f, 0.0f)); v2 = sBoxModel.AddVertex(new Vector3(DELTA, -DELTA, DELTA), new Vector3(0.0f, -1.0f, 0.0f), new Vector2(1.0f, 0.0f)); v3 = sBoxModel.AddVertex(new Vector3(DELTA, -DELTA, -DELTA), new Vector3(0.0f, -1.0f, 0.0f), new Vector2(1.0f, 1.0f)); sBoxModel.AddTriangle(v0, v1, v2); sBoxModel.AddTriangle(v2, v3, v0); sBoxModel.EndCreateNewMesh(); } return sBoxModel; } private static CustomModel sBeveledCubeModel; public static CustomModel GetBeveledCube() { if (null == sBeveledCubeModel) { //Create the box model. sBeveledCubeModel = new CustomModel(); sBeveledCubeModel.BeginCreateNewMesh(); const float BOX_RADIUS = 0.5f; const float BEVEL_RADIUS = 0.15f; const int NUM_SUB_DIVISIONS = 3; const float FACE_SIZE = (BOX_RADIUS - BEVEL_RADIUS); int v0, v1, v2, v3; //Front face v0 = sBeveledCubeModel.AddVertex(new Vector3(-FACE_SIZE, -FACE_SIZE, BOX_RADIUS), new Vector3(0.0f, 0.0f, 1.0f), new Vector2(0.0f, 1.0f)); v1 = sBeveledCubeModel.AddVertex(new Vector3(-FACE_SIZE, FACE_SIZE, BOX_RADIUS), new Vector3(0.0f, 0.0f, 1.0f), new Vector2(0.0f, 0.0f)); v2 = sBeveledCubeModel.AddVertex(new Vector3(FACE_SIZE, FACE_SIZE, BOX_RADIUS), new Vector3(0.0f, 0.0f, 1.0f), new Vector2(1.0f, 0.0f)); v3 = sBeveledCubeModel.AddVertex(new Vector3(FACE_SIZE, -FACE_SIZE, BOX_RADIUS), new Vector3(0.0f, 0.0f, 1.0f), new Vector2(1.0f, 1.0f)); sBeveledCubeModel.AddTriangle(v0, v1, v2); sBeveledCubeModel.AddTriangle(v2, v3, v0); //Back face v0 = sBeveledCubeModel.AddVertex(new Vector3(-FACE_SIZE, -FACE_SIZE, -BOX_RADIUS), new Vector3(0.0f, 0.0f, -1.0f), new Vector2(1.0f, 1.0f)); v1 = sBeveledCubeModel.AddVertex(new Vector3(-FACE_SIZE, FACE_SIZE, -BOX_RADIUS), new Vector3(0.0f, 0.0f, -1.0f), new Vector2(1.0f, 0.0f)); v2 = sBeveledCubeModel.AddVertex(new Vector3(FACE_SIZE, FACE_SIZE, -BOX_RADIUS), new Vector3(0.0f, 0.0f, -1.0f), new Vector2(0.0f, 0.0f)); v3 = sBeveledCubeModel.AddVertex(new Vector3(FACE_SIZE, -FACE_SIZE, -BOX_RADIUS), new Vector3(0.0f, 0.0f, -1.0f), new Vector2(0.0f, 1.0f)); sBeveledCubeModel.AddTriangle(v0, v2, v1); sBeveledCubeModel.AddTriangle(v2, v0, v3); //Right face v0 = sBeveledCubeModel.AddVertex(new Vector3(BOX_RADIUS, -FACE_SIZE, -FACE_SIZE), new Vector3(1.0f, 0.0f, 0.0f), new Vector2(0.0f, 1.0f)); v1 = sBeveledCubeModel.AddVertex(new Vector3(BOX_RADIUS, FACE_SIZE, -FACE_SIZE), new Vector3(1.0f, 0.0f, 0.0f), new Vector2(0.0f, 0.0f)); v2 = sBeveledCubeModel.AddVertex(new Vector3(BOX_RADIUS, FACE_SIZE, FACE_SIZE), new Vector3(1.0f, 0.0f, 0.0f), new Vector2(1.0f, 0.0f)); v3 = sBeveledCubeModel.AddVertex(new Vector3(BOX_RADIUS, -FACE_SIZE, FACE_SIZE), new Vector3(1.0f, 0.0f, 0.0f), new Vector2(1.0f, 1.0f)); sBeveledCubeModel.AddTriangle(v0, v2, v1); sBeveledCubeModel.AddTriangle(v2, v0, v3); //Left face v0 = sBeveledCubeModel.AddVertex(new Vector3(-BOX_RADIUS, -FACE_SIZE, -FACE_SIZE), new Vector3(-1.0f, 0.0f, 0.0f), new Vector2(0.0f, 1.0f)); v1 = sBeveledCubeModel.AddVertex(new Vector3(-BOX_RADIUS, FACE_SIZE, -FACE_SIZE), new Vector3(-1.0f, 0.0f, 0.0f), new Vector2(0.0f, 0.0f)); v2 = sBeveledCubeModel.AddVertex(new Vector3(-BOX_RADIUS, FACE_SIZE, FACE_SIZE), new Vector3(-1.0f, 0.0f, 0.0f), new Vector2(1.0f, 0.0f)); v3 = sBeveledCubeModel.AddVertex(new Vector3(-BOX_RADIUS, -FACE_SIZE, FACE_SIZE), new Vector3(-1.0f, 0.0f, 0.0f), new Vector2(1.0f, 1.0f)); sBeveledCubeModel.AddTriangle(v0, v1, v2); sBeveledCubeModel.AddTriangle(v2, v3, v0); //Top face v0 = sBeveledCubeModel.AddVertex(new Vector3(-FACE_SIZE, BOX_RADIUS, -FACE_SIZE), new Vector3(0.0f, 1.0f, 0.0f), new Vector2(0.0f, 1.0f)); v1 = sBeveledCubeModel.AddVertex(new Vector3(-FACE_SIZE, BOX_RADIUS, FACE_SIZE), new Vector3(0.0f, 1.0f, 0.0f), new Vector2(0.0f, 0.0f)); v2 = sBeveledCubeModel.AddVertex(new Vector3(FACE_SIZE, BOX_RADIUS, FACE_SIZE), new Vector3(0.0f, 1.0f, 0.0f), new Vector2(1.0f, 0.0f)); v3 = sBeveledCubeModel.AddVertex(new Vector3(FACE_SIZE, BOX_RADIUS, -FACE_SIZE), new Vector3(0.0f, 1.0f, 0.0f), new Vector2(1.0f, 1.0f)); sBeveledCubeModel.AddTriangle(v0, v2, v1); sBeveledCubeModel.AddTriangle(v2, v0, v3); //Bottom face v0 = sBeveledCubeModel.AddVertex(new Vector3(-FACE_SIZE, -BOX_RADIUS, -FACE_SIZE), new Vector3(0.0f, -1.0f, 0.0f), new Vector2(0.0f, 1.0f)); v1 = sBeveledCubeModel.AddVertex(new Vector3(-FACE_SIZE, -BOX_RADIUS, FACE_SIZE), new Vector3(0.0f, -1.0f, 0.0f), new Vector2(0.0f, 0.0f)); v2 = sBeveledCubeModel.AddVertex(new Vector3(FACE_SIZE, -BOX_RADIUS, FACE_SIZE), new Vector3(0.0f, -1.0f, 0.0f), new Vector2(1.0f, 0.0f)); v3 = sBeveledCubeModel.AddVertex(new Vector3(FACE_SIZE, -BOX_RADIUS, -FACE_SIZE), new Vector3(0.0f, -1.0f, 0.0f), new Vector2(1.0f, 1.0f)); sBeveledCubeModel.AddTriangle(v0, v1, v2); sBeveledCubeModel.AddTriangle(v2, v3, v0); // Now add in the 12 edges AddBeveledEdge(sBeveledCubeModel, new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledEdge(sBeveledCubeModel, new Vector3(0.0f, 1.0f, 0.0f), new Vector3(-1.0f, 0.0f, 0.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledEdge(sBeveledCubeModel, new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(0.0f, -1.0f, 0.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledEdge(sBeveledCubeModel, new Vector3(0.0f, -1.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledEdge(sBeveledCubeModel, new Vector3(0.0f, 0.0f, 1.0f), new Vector3(0.0f, 1.0f, 0.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledEdge(sBeveledCubeModel, new Vector3(0.0f, -1.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledEdge(sBeveledCubeModel, new Vector3(0.0f, 0.0f, -1.0f), new Vector3(0.0f, -1.0f, 0.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledEdge(sBeveledCubeModel, new Vector3(0.0f, 1.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledEdge(sBeveledCubeModel, new Vector3(0.0f, 0.0f, 1.0f), new Vector3(-1.0f, 0.0f, 0.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledEdge(sBeveledCubeModel, new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledEdge(sBeveledCubeModel, new Vector3(0.0f, 0.0f, -1.0f), new Vector3(1.0f, 0.0f, 0.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledEdge(sBeveledCubeModel, new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); // And now for the 8 corners. AddBeveledCorner(sBeveledCubeModel, new Vector3(0.0f, 0.0f, 1.0f), new Vector3(0.0f, 1.0f, 0.0f), new Vector3(-1.0f, 0.0f, 0.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledCorner(sBeveledCubeModel, new Vector3(0.0f, 0.0f, 1.0f), new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(0.0f, -1.0f, 0.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledCorner(sBeveledCubeModel, new Vector3(0.0f, 0.0f, 1.0f), new Vector3(0.0f, -1.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledCorner(sBeveledCubeModel, new Vector3(0.0f, 0.0f, 1.0f), new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledCorner(sBeveledCubeModel, new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledCorner(sBeveledCubeModel, new Vector3(0.0f, -1.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledCorner(sBeveledCubeModel, new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(0.0f, -1.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); AddBeveledCorner(sBeveledCubeModel, new Vector3(0.0f, 1.0f, 0.0f), new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), BOX_RADIUS, BEVEL_RADIUS, NUM_SUB_DIVISIONS); sBeveledCubeModel.EndCreateNewMesh(); } return sBeveledCubeModel; } private static void AddBeveledCorner(CustomModel model, Vector3 faceForward, Vector3 faceUp, Vector3 faceLeft, float boxRadius, float bevelRadius, int numSubDivisions) { const int MAX_TRIANGLES = 256; SubDTriangle[] triangles1 = new SubDTriangle[MAX_TRIANGLES]; SubDTriangle[] triangles2 = new SubDTriangle[MAX_TRIANGLES]; // Create the main triangle. We use angles and it is a triangle open at the top. SubDEdge edge0 = new SubDEdge(); SubDEdge edge1 = new SubDEdge(); SubDEdge edge2 = new SubDEdge(); // Since we are doing things in angle space, we break apart the top of the main triangle // before subdividing. // // (0,1) (1,1) // | | // 0| |2 // |___1__| // (0,0) (1,0) edge0.Setup(new Vector3(0.0f, 1.0f, 0.0f), new Vector3(0.0f, 0.0f, 0.0f)); edge1.Setup(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f)); edge2.Setup(new Vector3(1.0f, 0.0f, 0.0f), new Vector3(1.0f, 1.0f, 0.0f)); triangles1[0].Setup(edge0, edge1, edge2); int triangleCount = 1; // Subdivide the triangle for the number of recursive steps. for (int subDCount = 0; subDCount < numSubDivisions; ++subDCount) { int newTriCount = 0; for (int currTri = 0; currTri < triangleCount; ++currTri) { triangles1[currTri].Subdivide(ref triangles2[newTriCount], ref triangles2[newTriCount+1], ref triangles2[newTriCount+2], ref triangles2[newTriCount+3]); newTriCount += 4; } //Now swap the pointers to the arrays for the next iteration. SubDTriangle[] tempTriangles; tempTriangles = triangles1; triangles1 = triangles2; triangles2 = tempTriangles; triangleCount = newTriCount; } //triangles1 now contains all the new list of subdivided triangles. Vector3 offset = (faceForward + faceUp - faceLeft) * (boxRadius - bevelRadius); float scale = bevelRadius; //Now add in all the triangles. for (int i = 0; i < triangleCount; ++i) { Vector3 p0 = ConvertToWorldSpace(triangles1[i].mEdge0.mP0, faceForward, faceUp, faceLeft ); Vector3 p1 = ConvertToWorldSpace(triangles1[i].mEdge1.mP0, faceForward, faceUp, faceLeft); Vector3 p2 = ConvertToWorldSpace(triangles1[i].mEdge2.mP0, faceForward, faceUp, faceLeft); //MDS_TODO put in decent texture coords here. int v0 = model.AddVertex(p0 * scale + offset, p0, Vector2.Zero); int v1 = model.AddVertex(p1 * scale + offset, p1, Vector2.Zero); int v2 = model.AddVertex(p2 * scale + offset, p2, Vector2.Zero); model.AddTriangle(v0, v1, v2); } } private static Vector3 ConvertToWorldSpace(Vector3 angleSpacePoint, Vector3 faceForward, Vector3 faceUp, Vector3 faceLeft) { const float HALF_PI = (float)Math.PI * 0.5f; //return angleSpacePoint; // The x component is the yaw (around the up vector). Matrix m = Matrix.CreateFromAxisAngle(faceUp, angleSpacePoint.Y * HALF_PI ); // The y component is the pitch (around the right vector). m *= Matrix.CreateFromAxisAngle(faceLeft, angleSpacePoint.X * HALF_PI); // Add in a triangle based on the values in the subD triangles. return Vector3.TransformNormal(faceForward, m); } private static void AddBeveledEdge(CustomModel model, Vector3 faceForward, Vector3 faceUp, float boxRadius, float bevelRadius, int numSubDivisions) { const float HALF_PI = (float)Math.PI * 0.5f; int numSegments = 1; for (int i=0; i