public static PolygonSoupChunk Read(BinaryReader br) { PolygonSoupChunk result = new PolygonSoupChunk(); result.Position = br.ReadVector3I(); result.Scale = br.ReadSingle(); uint propertyListStart = br.ReadUInt32(); uint pointListStart = br.ReadUInt32(); br.ReadInt16(); // Length byte propertyListCount = br.ReadByte(); result.QuadCount = br.ReadByte(); int pointCount = br.ReadByte(); result.Unknown10 = br.ReadByte(); result.Unknown11 = br.ReadInt16(); br.BaseStream.Position = pointListStart; for (int i = 0; i < pointCount; i++) { result.PointList.Add(br.ReadVector3S()); } br.BaseStream.Position = propertyListStart; for (int i = 0; i < propertyListCount; i++) { result.PropertyList.Add(PolygonSoupProperty.Read(br)); } return(result); }
public Mesh BuildMesh(Vector3I pos, float scale) { Mesh mesh = new Mesh(); mesh.Faces = new List <MeshFace>(); for (int i = 0; i < PropertyList.Count; i++) { MeshFace face = new MeshFace(); PolygonSoupProperty property = PropertyList[i]; face.Indices.Add(property.Indices[0]); face.Indices.Add(property.Indices[1]); face.Indices.Add(property.Indices[2]); ushort unknownProperty1 = (ushort)(property.UnknownProperty & 0xFFFF); ushort unknownProperty2 = (ushort)((property.UnknownProperty >> 16)); // & 0xFFFF); string unknownBytes = property.UnknownBytes[0].ToString("X2") + "_" + property.UnknownBytes[1].ToString("X2") + "_" + property.UnknownBytes[2].ToString("X2") + "_" + property.UnknownBytes[3].ToString("X2"); face.Material = new Material( unknownProperty1.ToString("X4") + "_" + unknownProperty2.ToString("X4") + "_" + unknownBytes, Color.White); mesh.Faces.Add(face); if (property.Indices[3] != 0xFF) { MeshFace face2 = new MeshFace(); face2.Material = face.Material; face2.Indices.Add(property.Indices[3]); face2.Indices.Add(property.Indices[2]); face2.Indices.Add(property.Indices[1]); mesh.Faces.Add(face2); } } List <Vector3S> points = PointList; for (int i = 0; i < points.Count; i++) { Vector3S vert = points[i]; mesh.Vertices.Add(new Vector3((vert.X + pos.X) * scale, (vert.Y + pos.Y) * scale, (vert.Z + pos.Z) * scale)); } return(mesh); }
public PolygonSoupProperty Copy() { PolygonSoupProperty result = new PolygonSoupProperty(); result.UnknownProperty = UnknownProperty; for (int i = 0; i < Indices.Length; i++) { result.Indices[i] = Indices[i]; } for (int i = 0; i < UnknownBytes.Length; i++) { result.UnknownBytes[i] = UnknownBytes[i]; } return(result); }
public static PolygonSoupProperty Read(BinaryReader br) { PolygonSoupProperty result = new PolygonSoupProperty(); result.UnknownProperty = br.ReadUInt32(); for (int i = 0; i < result.Indices.Length; i++) { result.Indices[i] = br.ReadByte(); } for (int i = 0; i < result.UnknownBytes.Length; i++) { result.UnknownBytes[i] = br.ReadByte(); } return(result); }
public void ImportObj(string path) { GenericModel model = OBJImporter.ImportOBJ(path); model.SplitByPointCount(255); // Verify data before applying foreach (GenericMesh mesh in model.Meshes) { // Get highest point uint pointCount = 0; foreach (uint key in mesh.Vertices.Keys) { if (pointCount < key) { pointCount = key; } } pointCount++; // Is it too big for a byte? if (pointCount > 256) { throw new ReadFailedError("Too many points for mesh: " + mesh.Name + ", " + pointCount + " > 256"); } foreach (Face face in mesh.Faces) { // Triangulation required for now. if (face.Indices.Count > 3) { throw new ReadFailedError("Please triangulate your mesh: " + mesh.Name); } // Material names are required if (string.IsNullOrEmpty(face.Material?.Name)) { throw new ReadFailedError("Invalid Material for mesh: " + mesh.Name); } // Verify that all data is there string[] split = face.Material.Name.Split('_'); if (split.Length < 7) { throw new ReadFailedError("Invalid Material Data: " + face.Material.Name + ", for mesh: " + mesh.Name); } // Verify that all data can be parsed try { Utilities.Parse(split[1], true, out ushort _); Utilities.Parse(split[2], true, out ushort _); Utilities.Parse(split[3], true, out byte _); Utilities.Parse(split[4], true, out byte _); Utilities.Parse(split[5], true, out byte _); Utilities.Parse(split[6], true, out byte _); } catch (NotSupportedException) { throw new ReadFailedError("Unable to Parse Material Data: " + face.Material.Name + ", for mesh: " + mesh.Name); } } } // Clear existing data Chunks.Clear(); BoundingBoxes.Clear(); // Global vertices list to calculate the bounding box List <Vector3> vertices = new List <Vector3>(); // Generate PolygonSoupChunks and BoundingBoxes foreach (GenericMesh mesh in model.Meshes) { PolygonSoupChunk chunk = new PolygonSoupChunk(); foreach (Face face in mesh.Faces) { PolygonSoupProperty property = new PolygonSoupProperty(); // Set Indices property.Indices[0] = (byte)face.Indices[0]; property.Indices[1] = (byte)face.Indices[1]; property.Indices[2] = (byte)face.Indices[2]; if (face.Indices.Count > 3) { property.Indices[3] = (byte)face.Indices[3]; } else { property.Indices[3] = 0xFF; } // Get data from material name string materialName = face.Material.Name; string[] split = materialName.Split('_'); // Parse the values Utilities.Parse(split[1], true, out ushort unknownProperty1); Utilities.Parse(split[2], true, out ushort unknownProperty2); Utilities.Parse(split[3], true, out byte unknownByte1); Utilities.Parse(split[4], true, out byte unknownByte2); Utilities.Parse(split[5], true, out byte unknownByte3); Utilities.Parse(split[6], true, out byte unknownByte4); // Combine unknownProperty1 and unknownProperty2 property.UnknownProperty = (uint)((unknownProperty2 << 16) | unknownProperty1); // Set unknown bytes property.UnknownBytes[0] = unknownByte1; property.UnknownBytes[1] = unknownByte2; property.UnknownBytes[2] = unknownByte3; property.UnknownBytes[3] = unknownByte4; // Add the property chunk.PropertyList.Add(property); } // Add the vertices to the global vertices list vertices.AddRange(mesh.Vertices.Values.ToArray()); // Get the minimum and maximum point of the mesh Vector3 min = MathUtils.MinBounds(mesh.Vertices.Values.ToArray()); Vector3 max = MathUtils.MaxBounds(mesh.Vertices.Values.ToArray()); // Use the minimum as the position Vector3 position = min; // Set the scale to something standard float scale = 0.015f; // Get the point count uint pointCount = 0; foreach (uint key in mesh.Vertices.Keys) { if (pointCount < key) { pointCount = key; } } pointCount++; Vector3S[] verts = new Vector3S[pointCount]; foreach (uint key in mesh.Vertices.Keys) { // Convert the point to a short and apply position and scale verts[key] = new Vector3S((mesh.Vertices[key] - position) / scale); } chunk.PointList = verts.ToList(); // Quads are currently unsupported chunk.QuadCount = 0; chunk.Scale = scale; // Set the position and apply scale chunk.Position = new Vector3I(position / scale); // Add the chunk Chunks.Add(chunk); // Add the bounding box BoundingBoxes.Add(new PolygonSoupBoundingBox(new BoxF(min, max), -1)); } // Calculate Bounding Box Min = MathUtils.MinBounds(vertices.ToArray()); Max = MathUtils.MaxBounds(vertices.ToArray()); }