public TriangleStripper(ModelBase.FaceListDef faceList) { if (faceList.m_Type != ModelBase.PolyListType.Triangles) { bool tris = true; for (int i = 0; i < faceList.m_Faces.Count; i++) { tris = (faceList.m_Faces[i].m_NumVertices == 3); if (!tris) { throw new ArgumentException("The provided FaceListDef must be triangulated."); } } faceList.m_Type = ModelBase.PolyListType.Triangles; } m_Vertices = new List <VertexLinked>(); m_Triangles = new List <TriangleLinked>(); m_TrianglesToProcess = new List <TriangleLinked>(); for (int i = 0; i < faceList.m_Faces.Count; i++) { if (IsDegenerateFace(faceList.m_Faces[i])) { faceList.m_Faces.RemoveAt(i); } } for (int i = 0; i < faceList.m_Faces.Count; i++) { m_Triangles.Add(new TriangleLinked(faceList.m_Faces[i])); } for (int i = 0; i < m_Triangles.Count; i++) { ModelBase.FaceDef triangle = m_Triangles[i].m_Triangle; for (int j = 0; j < triangle.m_NumVertices; j++) { VertexLinked vertex = new VertexLinked(triangle.m_Vertices[j]); int index = m_Vertices.IndexOf(vertex); if (index == -1) { m_Vertices.Add(vertex); index = m_Vertices.Count - 1; } m_Vertices[index].m_LinkedTriangles.Add(i); } } }
Tuple <ModelBase.FaceListDef, List <int> > GetStripAndIndicesForStartingEvenEdge( TriangleLinked start, TriangleEdge startForwardEdge) { List <int> stripIndices = new List <int>(); List <TriangleRotation> stripRotations = new List <TriangleRotation>(); List <TriangleLinked> linked = GetLinked(start)[(int)startForwardEdge]; TriangleLinked bestNeighbour = DetermineBestNextNeighbour(start, linked, startForwardEdge); if (bestNeighbour == null) { return(new Tuple <ModelBase.FaceListDef, List <int> >(new ModelBase.FaceListDef(), new List <int>())); } TriangleRotation startRotation = (TriangleRotation)((int)(startForwardEdge - TriangleEdge.Edge_BC + 3) % 3); TriangleLinked t = start; TriangleEdge currentEdge = startForwardEdge; TriangleRotation currentRotation = startRotation; bool even = true; int index_t = -1; while (t != null && !stripIndices.Contains((index_t = m_Triangles.IndexOf(t)))) { stripIndices.Add(index_t); stripRotations.Add(currentRotation); linked = GetLinked(t)[(int)currentEdge]; bestNeighbour = DetermineBestNextNeighbour(t, linked, currentEdge); t = bestNeighbour; even = !even; if (t != null) { // Determine rotation and the edge to be used to get the next face ModelBase.FaceDef triangleC_CW = new ModelBase.FaceDef(3); if (even) { triangleC_CW.m_Vertices[0] = t.m_Triangle.m_Vertices[0]; triangleC_CW.m_Vertices[1] = t.m_Triangle.m_Vertices[1]; triangleC_CW.m_Vertices[2] = t.m_Triangle.m_Vertices[2]; } else { triangleC_CW.m_Vertices[0] = t.m_Triangle.m_Vertices[2]; triangleC_CW.m_Vertices[1] = t.m_Triangle.m_Vertices[1]; triangleC_CW.m_Vertices[2] = t.m_Triangle.m_Vertices[0]; } // The edge of the vertices which match the preceding triangle's TriangleEdge linkBackEdge = TriangleEdge.Edge_AB; // The vertices which match the preceding triangle's ModelBase.VertexDef[] currentMatchedEdge = new ModelBase.VertexDef[2]; TriangleLinked previous = m_Triangles[stripIndices[stripIndices.Count - 1]]; currentMatchedEdge[0] = previous.m_Triangle.m_Vertices[(int)(currentEdge + 0) % 3]; currentMatchedEdge[1] = previous.m_Triangle.m_Vertices[(int)(currentEdge + 1) % 3]; // Find the edge in the current triangle which if odd has been made CW which matches // that from the preceding triangle. This will be set as the current triangle's first, // or 'AB' edge and the next edge (next two vertices) will be used to match the next // triangle. for (int i = 0; i < 3; i++) { ModelBase.VertexDef[] edge = new ModelBase.VertexDef[2]; edge[0] = triangleC_CW.m_Vertices[(i + 0) % 3]; edge[1] = triangleC_CW.m_Vertices[(i + 1) % 3]; if (edge.Except(currentMatchedEdge).Count() == 0) { linkBackEdge = (TriangleEdge)i; break; } } TriangleEdge nextEdgeNoC_CW = (TriangleEdge)((int)(linkBackEdge + 1) % 3); TriangleEdge nextEdge = nextEdgeNoC_CW; if (!even) { // If odd, nextEdgeNoC_CW points to the edge to be used if written CW, however // all triangles have been read in as CCW so need to get the corresponding edge // in CCW version. ModelBase.VertexDef[] nextEdgeNoC_CW_Vertices = new ModelBase.VertexDef[2]; nextEdgeNoC_CW_Vertices[0] = triangleC_CW.m_Vertices[(int)(nextEdgeNoC_CW + 0) % 3]; nextEdgeNoC_CW_Vertices[1] = triangleC_CW.m_Vertices[(int)(nextEdgeNoC_CW + 1) % 3]; for (int i = 0; i < 3; i++) { ModelBase.VertexDef[] ccwEdge = new ModelBase.VertexDef[2]; ccwEdge[0] = t.m_Triangle.m_Vertices[(i + 0) % 3]; ccwEdge[1] = t.m_Triangle.m_Vertices[(i + 1) % 3]; if (nextEdgeNoC_CW_Vertices.Except(ccwEdge).Count() == 0) { nextEdge = (TriangleEdge)i; break; } } } // Now we need to determine the required rotation of the current triangle so that for // even triangles the new vertex in at index 0 and for odd triangles it occurs at // index 2. ModelBase.VertexDef uniqueVertex = t.m_Triangle.m_Vertices.Except(previous.m_Triangle.m_Vertices).ElementAt(0); int uniqueVertexIndex = Array.IndexOf(t.m_Triangle.m_Vertices, uniqueVertex); TriangleRotation requiredRotation = (even) ? (TriangleRotation)((uniqueVertexIndex - 2 + 3) % 3) : (TriangleRotation)(uniqueVertexIndex); currentRotation = requiredRotation; currentEdge = nextEdge; // To best understand how this works, debug and step-through how the following model is handled: // // An example: // Faces as defined in model (all Counter-Clockwise (CCW)): // f 1 2 3 // f 4 1 3 // f 4 5 1 // Build strip from edge CA. // # 2 3 1 (LS) <- Need to Left Shift vertices so that CA is the second edge (in a tri. strip it's // always the second edge that's shared - see diagram at top). // # 3 1 4 (4 1 3) <- For odd faces the new vertex must be at index [0] // No Rot required, link-back CW: AB, CW forward: AB + 1 = BC, // CCW forward: edge in CCW that contains vertices in (CW forward) = AB // The next triangle is the one that shares the CCW edge AB (vertices 1 and 4) // # 1 4 5 (RS) <- Even face the new vertex needs to be in index [2] so need to Right Shift vertices // Repeat steps as for above face but don't need to worry about converting between CCW and CW order } } ModelBase.FaceListDef tStrip = new ModelBase.FaceListDef(ModelBase.PolyListType.TriangleStrip); for (int i = 0; i < stripIndices.Count; i++) { TriangleRotation requiredRotation = (TriangleRotation)stripRotations[i]; ModelBase.FaceDef rotated = new ModelBase.FaceDef(3); rotated.m_Vertices[0] = m_Triangles[stripIndices[i]].m_Triangle.m_Vertices[((int)(0 + requiredRotation) % 3)]; rotated.m_Vertices[1] = m_Triangles[stripIndices[i]].m_Triangle.m_Vertices[((int)(1 + requiredRotation) % 3)]; rotated.m_Vertices[2] = m_Triangles[stripIndices[i]].m_Triangle.m_Vertices[((int)(2 + requiredRotation) % 3)]; tStrip.m_Faces.Add(rotated); } return(new Tuple <ModelBase.FaceListDef, List <int> >(tStrip, stripIndices)); }
// Return true if two of a triangle's vertices are the same private bool IsDegenerateFace(ModelBase.FaceDef triangle) { return(triangle.m_Vertices.ToList().Except(triangle.m_Vertices.ToList()).Count() != 0); }