/// <summary> /// Searches for the halfedge pointing to the specified face from this vertex. /// </summary> /// <param name="face">The face the halfedge to find points to.</param> /// <returns>The halfedge if it is found, otherwise null.</returns> public DXHalfedge FindHalfedgeTo(DXFace face) { foreach (DXHalfedge h in Halfedges) { if (h.Face == face) { return(h); } } return(null); }
/// <summary> /// Determines if two faces are adjacent. /// </summary> /// <param name="faceA">One of the faces to search for.</param> /// <param name="faceB">The other face to search for.</param> /// <returns>True if the faces are adjacent, false if they are not.</returns> public static bool FacesShareEdge(DXFace faceA, DXFace faceB) { foreach (DXFace f in faceA.Faces) { if (f == faceB) { return(true); } } return(false); }
private void ImportMesh(Section section, ImportedMesh meshList, SortedDictionary<string, byte> boneDic, List<bool> hasBonesList) { int vertIdxOffset = 0; foreach (ImportedSubmesh submesh in meshList.SubmeshList) { vertIdxOffset += submesh.VertexList.Count; } LinkedListNode<object> node = section.data.First; int numVertices = ConvertInt32(node.Value); node = node.Next; DXVertex[] vertices = new DXVertex[numVertices]; for (int i = 0; i < numVertices; i++) { vertices[i] = new DXVertex(); float[] pos = new float[3]; for (int j = 0; j < pos.Length; j++) { pos[j] = ConvertFloat(node.Value); node = node.Next; } pos[2] = -pos[2]; vertices[i].position = pos; } int numFaces = ConvertInt32(node.Value); node = node.Next; DXFace[] faces = new DXFace[numFaces]; for (int i = 0; i < numFaces; i++) { int numFaceVerts = ConvertInt32(node.Value); node = node.Next; if (numFaceVerts != 3) { throw new Exception("Meshes must be triangulated"); } faces[i] = new DXFace(); faces[i].vertexIndices[0] = ConvertUInt16(node.Value); node = node.Next; faces[i].vertexIndices[2] = ConvertUInt16(node.Value); node = node.Next; faces[i].vertexIndices[1] = ConvertUInt16(node.Value); node = node.Next; } string[] materials = new string[] { String.Empty }; bool hasNormals = false; bool hasBones = false; bool hasUVs = false; List<KeyValuePair<byte, float>>[] boneAssignments = new List<KeyValuePair<byte, float>>[numVertices]; for (int i = 0; i < boneAssignments.Length; i++) { boneAssignments[i] = new List<KeyValuePair<byte, float>>(); } foreach (Section child in section.children) { if (child.type == "VertexDuplicationIndices") { } else if (child.type == "MeshNormals") { hasNormals = true; LinkedListNode<object> childNode = child.data.First; int numNormals = ConvertInt32(childNode.Value); childNode = childNode.Next; if (numNormals != numVertices) { throw new Exception("Number of normals doesn't match the number of vertices"); } foreach (DXVertex vert in vertices) { float[] norm = new float[3]; for (int i = 0; i < norm.Length; i++) { norm[i] = ConvertFloat(childNode.Value); childNode = childNode.Next; } norm[2] = -norm[2]; vert.normal = norm; } } else if (child.type == "MeshTextureCoords") { hasUVs = true; LinkedListNode<object> childNode = child.data.First; int numTexCoords = ConvertInt32(childNode.Value); childNode = childNode.Next; if (numTexCoords != numVertices) { throw new Exception("Number of texture coordinates doesn't match the number of vertices"); } foreach (DXVertex vert in vertices) { float[] uv = new float[2]; for (int i = 0; i < uv.Length; i++) { uv[i] = ConvertFloat(childNode.Value); childNode = childNode.Next; } vert.uv = uv; } } else if (child.type == "MeshMaterialList") { materials = ImportMaterials(child, faces); } else if (child.type == "XSkinMeshHeader") { hasBones = true; } else if (child.type == "SkinWeights") { LinkedListNode<object> childNode = child.data.First; string boneName = ConvertString(childNode.Value); childNode = childNode.Next; int numWeights = ConvertInt32(childNode.Value); childNode = childNode.Next; int[] vertIndices = new int[numWeights]; for (int i = 0; i < numWeights; i++) { vertIndices[i] = ConvertInt32(childNode.Value); childNode = childNode.Next; } float[] weights = new float[numWeights]; for (int i = 0; i < numWeights; i++) { weights[i] = ConvertFloat(childNode.Value); childNode = childNode.Next; } byte boneIdx; if (!boneDic.TryGetValue(boneName, out boneIdx)) { boneIdx = (byte)boneDic.Count; boneDic.Add(boneName, boneIdx); ImportedBone boneInfo = new ImportedBone(); meshList.BoneList.Add(boneInfo); boneInfo.Name = boneName; Matrix matrix = new Matrix(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[i, j] = ConvertFloat(childNode.Value); childNode = childNode.Next; } } boneInfo.Matrix = RHToLHMatrix(matrix); } for (int i = 0; i < numWeights; i++) { boneAssignments[vertIndices[i]].Add(new KeyValuePair<byte, float>(boneIdx, weights[i])); } } else { Report.ReportLog("Warning: unexpected section " + child.type); } } if (hasBones) { for (int i = 0; i < boneAssignments.Length; i++) { byte[] boneIndices = new byte[4]; float[] weights4 = new float[4]; for (int j = 0; (j < 4) && (j < boneAssignments[i].Count); j++) { boneIndices[j] = boneAssignments[i][j].Key; weights4[j] = boneAssignments[i][j].Value; } for (int j = boneAssignments[i].Count; j < 4; j++) { boneIndices[j] = 0xFF; weights4[j] = 0; } vertices[i].boneIndices = boneIndices; vertices[i].weights = new float[] { weights4[0], weights4[1], weights4[2], weights4[3] }; } } SortedDictionary<ushort, ushort>[] vertexMaps = new SortedDictionary<ushort, ushort>[materials.Length]; ImportedSubmesh[] submeshes = new ImportedSubmesh[materials.Length]; for (int i = 0; i < materials.Length; i++) { submeshes[i] = new ImportedSubmesh(); submeshes[i].Material = materials[i]; submeshes[i].VertexList = new List<ImportedVertex>(vertices.Length); submeshes[i].FaceList = new List<ImportedFace>(faces.Length); vertexMaps[i] = new SortedDictionary<ushort, ushort>(); } foreach (DXFace dxFace in faces) { ImportedSubmesh submesh = submeshes[dxFace.materialIndex]; ImportedFace face = new ImportedFace(); submesh.FaceList.Add(face); ushort[] foundVertexIndices = new ushort[3]; for (int i = 0; i < dxFace.vertexIndices.Length; i++) { ushort dxVertIdx = dxFace.vertexIndices[i]; SortedDictionary<ushort, ushort> vertexMap = vertexMaps[dxFace.materialIndex]; if (!vertexMap.TryGetValue(dxVertIdx, out foundVertexIndices[i])) { DXVertex dxVert = vertices[dxVertIdx]; ImportedVertex vert = new ImportedVertex(); submesh.VertexList.Add(vert); if (hasNormals) { vert.Normal = new Vector3(dxVert.normal[0], dxVert.normal[1], dxVert.normal[2]); } if (hasUVs) { vert.UV = (float[])dxVert.uv.Clone(); } if (hasBones) { vert.BoneIndices = (byte[])dxVert.boneIndices.Clone(); vert.Weights = (float[])dxVert.weights.Clone(); } vert.Position = new Vector3(dxVert.position[0], dxVert.position[1], dxVert.position[2]); vertIdxOffset++; foundVertexIndices[i] = (ushort)vertexMap.Count; vertexMap.Add(dxVertIdx, foundVertexIndices[i]); } } face.VertexIndices = new int[] { foundVertexIndices[0], foundVertexIndices[1], foundVertexIndices[2] }; } foreach (ImportedSubmesh submesh in submeshes) { if (submesh.VertexList.Count > 0) { submesh.VertexList.TrimExcess(); submesh.FaceList.TrimExcess(); submesh.Index = meshList.SubmeshList.Count; meshList.SubmeshList.Add(submesh); hasBonesList.Add(hasBones); if (!hasNormals) { for (int i = 0; i < submesh.VertexList.Count; i++) { submesh.VertexList[i].Normal = new Vector3(); } } } } }
private string[] ImportMaterials(Section section, DXFace[] faces) { LinkedListNode<object> node = section.data.First; int numMaterials = ConvertInt32(node.Value); node = node.Next; if (numMaterials != section.children.Count) { throw new Exception("number of materials doesn't match number of children"); } int numFaces = ConvertInt32(node.Value); node = node.Next; if (numFaces != faces.Length) { throw new Exception("number of faces doesn't match with material"); } for (int i = 0; i < numFaces; i++) { faces[i].materialIndex = ConvertInt32(node.Value); node = node.Next; } string[] materialNames = new string[numMaterials]; for (int i = 0; i < numMaterials; i++) { Section matSection = section.children[i]; if (matSection.type == "Material") { string texName = String.Empty; foreach (Section texSection in matSection.children) { if (texSection.type == "TextureFilename") { texName = ImportTexture(texSection); break; } else { Report.ReportLog("Warning: unexpected section " + matSection.type); } } if (matSection.name == null) { if (texName == String.Empty) { materialNames[i] = "no_name_" + noNameCount; } else { materialNames[i] = Path.GetFileNameWithoutExtension(texName) + "_" + noNameCount; } noNameCount++; } else { materialNames[i] = matSection.name; } if (matList.Add(materialNames[i])) { LinkedListNode<object> dataNode = section.children[i].data.First; ImportedMaterial matInfo = new ImportedMaterial(); matInfo.Name = materialNames[i]; matInfo.Diffuse = new Color4(1, 1, 1, 1); float[] ambient = new float[4]; for (int j = 0; j < ambient.Length; j++) { ambient[j] = ConvertFloat(dataNode.Value); dataNode = dataNode.Next; } matInfo.Ambient = new Color4(ambient[3], ambient[0], ambient[1], ambient[2]); matInfo.Power = ConvertFloat(dataNode.Value); dataNode = dataNode.Next; float[] specular = new float[4]; for (int j = 0; j < 3; j++) { specular[j] = ConvertFloat(dataNode.Value); dataNode = dataNode.Next; } specular[3] = 1; matInfo.Specular = new Color4(specular[3], specular[0], specular[1], specular[2]); float[] emissive = new float[4]; for (int j = 0; j < 3; j++) { emissive[j] = ConvertFloat(dataNode.Value); dataNode = dataNode.Next; } emissive[3] = 1; matInfo.Emissive = new Color4(emissive[3], emissive[0], emissive[1], emissive[2]); if (texName != String.Empty) { matInfo.Textures = new string[] { texName }; } MaterialList.Add(matInfo); } } else if (matSection.type == "ref") { if (matSection.name != null) { materialNames[i] = matSection.name; } } else { Report.ReportLog("Warning: unexpected section " + matSection.type); } } return materialNames; }
/// <summary> /// Adds a face to the face list. /// </summary> /// <param name="face">The face to add.</param> protected void AppendToFaceList(DXFace face) { face.Index = faces.Count; faces.Add(face); }