private static void OutputVertices(bool scaleMesh, StringBuilder sb, RrfMesh mesh, int3 parentOffset) { sb.AppendLine($"# {mesh.VertexCount} Vertexes"); sb.AppendLine($"# {mesh.VertexAddressRange.Start}"); foreach (var v in mesh.Vertices) { var offsetV = new float3(mesh.Origin + parentOffset); var floatV = new float3(v.Coord); // Resize mesh if (scaleMesh) { offsetV /= 1000; offsetV /= 1000; floatV /= 1000; floatV /= 1000; } floatV += offsetV; if (v.AttributeId != 0) { var attrName = Enum.GetName(typeof(RrfAttribute), v.AttributeId); sb.AppendLine($"# Attribute {v.AttributeId} {attrName}"); } sb.AppendLine($"v {floatV.X} {floatV.Z} {-floatV.Y}"); } sb.AppendLine($"# {mesh.VertexAddressRange.End}"); }
private static void OutputFaces(RrfModel model, StringBuilder sb, RrfMesh mesh, int index) { sb.AppendLine($"# {mesh.FaceCount} Faces"); sb.AppendLine($"# {mesh.FaceAddressRange.Start}"); foreach (var face in mesh.Faces) { var vertexIndexOffset = 1 + model.Meshes.Take(index).Sum(f => f.VertexCount); sb.AppendLine( $"f {face.VertexIndexes[0] + vertexIndexOffset}" + $" {face.VertexIndexes[1] + vertexIndexOffset}" + $" {face.VertexIndexes[2] + vertexIndexOffset}" + (face.IsQuad ? $" {face.VertexIndexes[3] + vertexIndexOffset}" : string.Empty)); } sb.AppendLine($"# {mesh.FaceAddressRange.End}"); }
private static void LoadMeshHeaders(ref RrfModel rrfModel, ref FileStream fileStream) { for (var meshIndex = 0; meshIndex < rrfModel.MeshCount; meshIndex++) { var mesh = new RrfMesh { HeaderAddressRange = new AddressRange { Start = fileStream.Position } }; // Read mesh name at 0x14 const int maxNameLength = 0xC; for (var i = 0; i < maxNameLength; i++) { var nByte = fileStream.ReadByte(); // Escape on first 0 byte if (nByte == 0x0) { break; } mesh.Name += (char)nByte; } // Skip mesh name field var nameOffset = maxNameLength - mesh.Name.Length - 1; // Minus one because we read a null byte fileStream.Seek(nameOffset, SeekOrigin.Current); var nameEnd = fileStream.Position; mesh.Origin = new int3(fileStream.ReadInt32(), fileStream.ReadInt32(), fileStream.ReadInt32()); // Read bounds mesh.BoundingBox = new int3(fileStream.ReadInt32()); mesh.BoundingBoxOffset = new int3(fileStream.ReadInt32()); mesh.BoundingBox.Y = fileStream.ReadInt32(); mesh.BoundingBoxOffset.Y = fileStream.ReadInt32(); mesh.BoundingBox.Z = fileStream.ReadInt32(); mesh.BoundingBoxOffset.Z = fileStream.ReadInt32(); // Read unknown values const int unknownNumbersOffset = 0x44; while (fileStream.Position < nameEnd + unknownNumbersOffset) { mesh.UnknownPreTypeBytes.Add(fileStream.ReadInt32()); } // Mesh type byte at 0x64 mesh.Type = fileStream.ReadByte(); // Read unknown type bytes for (var i = 0; i < 0x3; i++) { mesh.UnknownTypeBytes.Add(fileStream.ReadByte()); } mesh.VertexCount = fileStream.ReadInt32(); // Skip terminating(?) FF FF FF FF bytes fileStream.Seek(0x4, SeekOrigin.Current); // Read child elements mesh.ChildCount = fileStream.ReadInt32(); for (var i = 0; i < mesh.ChildCount && mesh.ChildCount > 0; i++) { mesh.ChildMeshes.Add(fileStream.ReadInt32()); } // Skip remaining child elements range var unknownIntCount = (32 - mesh.ChildCount) * 4; // 4x to skip by int size fileStream.Seek(unknownIntCount, SeekOrigin.Current); // Read address ints mesh.UnknownZeroValue = fileStream.ReadInt32(); // RolloverIndex mesh.FaceCount = fileStream.ReadInt32(); mesh.FaceAddressRange = new AddressRange(fileStream.ReadInt32(), fileStream.ReadInt32()); mesh.DuplicateVertexValue = fileStream.ReadInt32(); // Duplicate(?) vertex count? mesh.VertexAddressRange = new AddressRange(fileStream.ReadInt32(), fileStream.ReadInt32()); mesh.UnknownAddressRange = new AddressRange(fileStream.ReadInt32(), fileStream.ReadInt32()); mesh.HeaderAddressRange.End = fileStream.Position; // Skip duplicate address patterns fileStream.Seek(0xFC, SeekOrigin.Current); rrfModel.Meshes.Add(mesh); } }