private (Vertex v, Normal n, UVCoordinate u) ParseVertex(string value, List <Vertex> vertices, List <Normal> normals, List <UVCoordinate> uvCoords, List <int> usedVertexIDs, List <int> usedNormalIDs) { string[] vertexData = value.Split('/'); int vertexID = int.Parse(vertexData[0]) - 1; Vertex vertex = vertices[vertexID]; usedVertexIDs.Add(vertexID); UVCoordinate uvCoord = null; if (vertexData.Length > 1 && vertexData[1] != "") { uvCoord = uvCoords[int.Parse(vertexData[1]) - 1]; } Normal normal = null; if (vertexData.Length > 2 && vertexData[2] != "") { int normalID = int.Parse(vertexData[2]) - 1; normal = normals[normalID]; usedNormalIDs.Add(normalID); } return(vertex, normal, uvCoord); }
public void ReadFromOBJ(TextReader reader, Stream unknownData) { if (unknownData != null) { Unknown1 = unknownData.ReadUShort(); Unknown2 = unknownData.ReadUShort(); Unknown3 = unknownData.ReadUShort(); Unknown4 = unknownData.ReadUShort(); unknownData.Read(Unknown5); } var lods = new LOD[3]; var wheelPositions = new WheelPosition[4]; string line; int currentWheelPosition = -1; short currentWheelPositionWValue = 0; int currentLODNumber = -1; bool shadow = false; string currentMaterial = "untextured"; Vertex wheelPositionCandidate = null; LOD currentLOD = null; var vertices = new List <Vertex>(); var normals = new List <Normal>(); var uvCoords = new List <UVCoordinate>(); var usedVertexIDs = new List <int>(); var usedNormalIDs = new List <int>(); int shadowVertexStartID = 0; double currentScale = 1; do { line = reader.ReadLine(); if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#")) { continue; } try { if (line.StartsWith("o ") || line.StartsWith("g ")) { string[] objectNameParts = line.Split(' ')[1].Split('/'); if (objectNameParts[0].StartsWith("wheelpos")) { currentWheelPosition = int.Parse(objectNameParts[0].Replace("wheelpos", "")); foreach (string namePart in objectNameParts) { string[] keyAndValue = namePart.Split('='); if (keyAndValue.Length == 2 && keyAndValue[0] == "w") { currentWheelPositionWValue = short.Parse(keyAndValue[1]); } } } else if (objectNameParts[0].StartsWith("lod")) { if (wheelPositions.Any(position => position == null)) { //throw new Exception("Expected four wheel position objects before any LOD objects."); // TODO: is this safe to remove? } if (currentLOD != null) { currentLOD.Vertices = usedVertexIDs.OrderBy(id => id).Distinct().Select(id => vertices[id]).ToList(); usedVertexIDs = new List <int>(); currentLOD.Normals = usedNormalIDs.OrderBy(id => id).Distinct().Select(id => normals[id]).ToList(); usedNormalIDs = new List <int>(); currentLOD.GenerateBoundingBox(); } currentLODNumber = int.Parse(objectNameParts[0].Replace("lod", "")); currentLOD = new LOD(); currentLOD.PrepareForOBJRead(unknownData); lods[currentLODNumber] = currentLOD; currentScale = GetScale(objectNameParts); currentLOD.Scale = LOD.ConvertScale(currentScale); } else if (objectNameParts[0].StartsWith("shadow")) { if (lods.Any(lod => lod == null)) { throw new Exception("Expected three LOD objects before shadow object."); } currentLOD.Vertices = usedVertexIDs.OrderBy(id => id).Distinct().Select(id => vertices[id]).ToList(); currentLOD.Normals = usedNormalIDs.OrderBy(id => id).Distinct().Select(id => normals[id]).ToList(); currentLOD.GenerateBoundingBox(); shadow = true; Shadow = new Shadow(); Shadow.PrepareForOBJRead(unknownData); shadowVertexStartID = vertices.Count; currentScale = GetScale(objectNameParts); Shadow.Scale = LOD.ConvertScale(currentScale); } } else if (line.StartsWith("v ")) { if (shadow) { var vertex = new ShadowVertex(); vertex.ReadFromOBJ(line, currentScale); Shadow.Vertices.Add(vertex); } else { var vertex = new Vertex(); vertex.ReadFromOBJ(line, currentScale); vertices.Add(vertex); if (currentLODNumber == -1) { wheelPositionCandidate = vertex; } } } else if (line.StartsWith("vt ")) { var uvCoord = new UVCoordinate(); uvCoord.ReadFromOBJ(line); uvCoords.Add(uvCoord); } else if (line.StartsWith("vn ")) { var normal = new Normal(); normal.ReadFromOBJ(line); normals.Add(normal); } else if (line.StartsWith("usemtl ")) { currentMaterial = line.Split(' ')[1]; } else if (line.StartsWith("f ")) { if (shadow) { var polygon = new ShadowPolygon(); polygon.ReadFromOBJ(line, Shadow.Vertices, shadowVertexStartID, currentMaterial); if (polygon.IsQuad) { Shadow.Quads.Add(polygon); } else { Shadow.Triangles.Add(polygon); } } else if (currentLODNumber == -1) { continue; //throw new Exception("Face found outside of a LOD or shadow."); } else if (currentMaterial.StartsWith("untextured")) { var polygon = new Polygon(); polygon.ReadFromOBJ(line, vertices, normals, currentMaterial, usedVertexIDs, usedNormalIDs); if (polygon.IsQuad) { currentLOD.Quads.Add(polygon); } else { currentLOD.Triangles.Add(polygon); } } else { var polygon = new UVPolygon(); polygon.ReadFromOBJ(line, vertices, normals, uvCoords, currentMaterial, usedVertexIDs, usedNormalIDs); if (polygon.IsQuad) { currentLOD.UVQuads.Add(polygon); } else { currentLOD.UVTriangles.Add(polygon); } } } if (currentWheelPosition != -1 && wheelPositionCandidate != null) { var position = new WheelPosition(); position.ReadFromOBJ(wheelPositionCandidate, currentWheelPositionWValue); wheelPositions[currentWheelPosition] = position; wheelPositionCandidate = null; currentWheelPosition = -1; } } catch (Exception exception) { throw new Exception($"Line:{line}\r\n{exception.Message}", exception); } }while (line != null); Shadow.GenerateBoundingBox(); LODs = lods.ToList(); WheelPositions = wheelPositions.ToList(); }
private string WriteVertexToOBJ(Vertex vertex, Normal normal, List <Vertex> vertices, List <Normal> normals, int firstVertexNumber, int firstNormalNumber, UVCoordinate coord, List <UVCoordinate> coords, int firstCoordNumber) => $"{vertices.IndexOf(vertex) + firstVertexNumber}/{coords.IndexOf(coord) + firstCoordNumber}/{normals.IndexOf(normal) + firstNormalNumber}";