Monday, May 17, 2010

Save XNA mesh with Managed DirectX

There are two options you can choose:

1. You can run the code with the OptimizeInPlace() line as it is and the mesh will be saved with the texture name in the material property. The mesh will not be valid if you load it in XNA. To correct this, open the mesh file (*.x) with Deep Exploration and save it again as a mesh file (*.x) and it will work with your XNA program. Be careful when you choose the "Save As..." options in Deep Exploration.

2. You can comment out the OptimizeInPlace() and the mesh will be saved without the texture name.

// Disable the loader lock MDA.
// Debug/Exceptions (ctrl-D, E), Open the Managed Debugging Assistants tree node and uncheck Loader Lock.
// This setting is per solution so it will only affect this solution.
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

public class MeshManager
{
Device device = null;

public MeshManager()
{
PresentParameters presentParams = new PresentParameters();

presentParams.Windowed = true;
presentParams.SwapEffect = SwapEffect.Discard;

System.Windows.Forms.Form renderWindow = new System.Windows.Forms.Form();

device = new Device(0, DeviceType.Hardware, renderWindow, CreateFlags.SoftwareVertexProcessing, presentParams);
}

public void SaveMesh(Microsoft.Xna.Framework.Graphics.VertexPositionNormalTexture[] verticesXna, short[] indicesXna,
int numVertices, int numFaces, string meshFilename, string textureFilename)
{
CustomVertex.PositionNormalTextured[] vertices = new CustomVertex.PositionNormalTextured[numVertices];

for (int i = 0; i < numVertices; ++i)
{
vertices[i].Position = new Vector3(verticesXna[i].Position.X, verticesXna[i].Position.Y, -verticesXna[i].Position.Z);
vertices[i].Normal = new Vector3(verticesXna[i].Normal.X, verticesXna[i].Normal.Y, -verticesXna[i].Normal.Z);
vertices[i].Tu = verticesXna[i].TextureCoordinate.X;
vertices[i].Tv = verticesXna[i].TextureCoordinate.Y;
}

short[] indices = new short[numFaces * 3];

for (int i = 0; i < numFaces * 3; i += 3)
{
indices[i + 0] = indicesXna[i + 0];
indices[i + 1] = indicesXna[i + 1];
indices[i + 2] = indicesXna[i + 2];
}

Mesh mesh = new Mesh(numFaces, numVertices, MeshFlags.Managed, CustomVertex.PositionNormalTextured.Format, device);

mesh.SetVertexBufferData(vertices, LockFlags.None);
mesh.SetIndexBufferData(indices, LockFlags.None);

int[] adjac = new int[mesh.NumberFaces * 3];
mesh.GenerateAdjacency(0.05f, adjac);
// Comment the next line to save a valid mesh. Material will not be saved.
mesh.OptimizeInPlace(MeshFlags.OptimizeVertexCache, adjac);

int subs = mesh.GetAttributeTable().Length;
ExtendedMaterial[] extmat = new ExtendedMaterial[subs];

Material material = new Material();
material.AmbientColor = new ColorValue(1.0f, 1.0f, 1.0f);
material.DiffuseColor = new ColorValue(1.0f, 1.0f, 1.0f);
material.EmissiveColor = new ColorValue(0.1f, 0.1f, 0.1f);
material.SpecularColor = new ColorValue(0.1f, 0.1f, 0.1f);
material.SpecularSharpness = 64.0f;

for (int i = 0; i < subs; i++)
{
extmat[i] = new ExtendedMaterial();
extmat[i].Material3D = material;
extmat[i].TextureFilename = textureFilename;
}

mesh.Save(meshFilename, adjac, extmat, XFileFormat.Text);
}
}