static VMeshRef ParseMeshPartNode(UTFNode meshPartNode) { if (meshPartNode.Nodes.Count > 0) { return(new VMeshRef(meshPartNode.Nodes[0].Data)); } return(null); }
static void ParseNode(BinaryReader reader, string stringBlock, int nodeBlockStart, int nodeStart, int dataBlockOffset, UTFNode parent) { int offset = nodeBlockStart + nodeStart; reader.BaseStream.Position = offset; int peerOffset = reader.ReadInt32(); // next node on same level int nameOffset = reader.ReadInt32(); // string for this node NodeFlags flags = (NodeFlags)reader.ReadInt32(); //int zero = reader.ReadInt32(); reader.BaseStream.Position += ByteLen.INT; UTFNode node = new UTFNode { Name = stringBlock.Substring(nameOffset, stringBlock.IndexOf('\0', nameOffset) - nameOffset) }; if ((flags & NodeFlags.Intermediate) == NodeFlags.Intermediate) { int childOffset = reader.ReadInt32(); if (childOffset > 0) { ParseNode(reader, stringBlock, nodeBlockStart, childOffset, dataBlockOffset, node); } //int allocatedSize = reader.ReadInt32(); //int size = reader.ReadInt32(); //int size2 = reader.ReadInt32(); //int timestamp1 = reader.ReadInt32(); //int timestamp2 = reader.ReadInt32(); //int timestamp3 = reader.ReadInt32(); } else if ((flags & NodeFlags.Leaf) == NodeFlags.Leaf) { int dataOffset = reader.ReadInt32(); //int allocatedSize = reader.ReadInt32(); reader.BaseStream.Position += ByteLen.INT; int size = reader.ReadInt32(); //int size2 = reader.ReadInt32(); //int timestamp1 = reader.ReadInt32(); //int timestamp2 = reader.ReadInt32(); //int timestamp3 = reader.ReadInt32(); reader.BaseStream.Position = dataBlockOffset + dataOffset; node.Data = reader.ReadBytes(size); } parent.Nodes.Add(node); if (peerOffset > 0) { ParseNode(reader, stringBlock, nodeBlockStart, peerOffset, dataBlockOffset, parent); } }
static VMeshRef ParseMultiLevelNode(UTFNode node) { foreach (UTFNode levelNode in node.Nodes) { if (levelNode.Name.Equals("level0", StringComparison.OrdinalIgnoreCase) && levelNode.Nodes.Count > 0) { return(ParseMeshPartNode(levelNode.Nodes[0])); } } return(null); }
public UTFNode Read() { using (FileStream stream = new FileStream(File, FileMode.Open, FileAccess.Read, FileShare.Read)) using (BinaryReader reader = new BinaryReader(stream)) { if (stream.Length < ByteLen.FILE_TAG + ByteLen.INT || Encoding.ASCII.GetString(reader.ReadBytes(ByteLen.FILE_TAG)) != FILE_TYPE || reader.ReadInt32() != FILE_VERSION) { return(null); } // get node info int nodeBlockOffset = reader.ReadInt32(); //int nodeBlockSize = reader.ReadInt32(); //int unknown1 = reader.ReadInt32(); //int header_size = reader.ReadInt32(); stream.Position += ByteLen.INT * 3; // get string info int stringBlockOffset = reader.ReadInt32(); int stringBlockSize = reader.ReadInt32(); //int unknown2 = reader.ReadInt32(); stream.Position += ByteLen.INT; // get data info int dataBlockOffset = reader.ReadInt32(); // goto string block stream.Position = stringBlockOffset; // read string block byte[] buffer = new byte[stringBlockSize]; reader.Read(buffer, 0, stringBlockSize); string stringBlock = Encoding.ASCII.GetString(buffer); UTFNode info = new UTFNode(); ParseNode(reader, stringBlock, nodeBlockOffset, 0, dataBlockOffset, info); return(info); } }
public static Model3D LoadModel(string file) { UTFManager utfManager = new UTFManager(file); UTFNode root = utfManager.Read(); if (root == null || root.Nodes.Count == 0) { return(null); } // select root (\) node root = root.Nodes[0]; Dictionary <uint, VMeshData> meshes = null; List <MeshReferenceMatch> meshReferenceNodes = new List <MeshReferenceMatch>(); List <CmpPart> constructs = new List <CmpPart>(); Dictionary <string, string> mapFileToObj = new Dictionary <string, string> { { "\\", "Model" } }; foreach (UTFNode node in root.Nodes) { switch (node.Name.ToLowerInvariant()) { case "vmeshlibrary": meshes = new Dictionary <uint, VMeshData>(node.Nodes.Count); foreach (UTFNode vmsNode in node.Nodes) { if (vmsNode.Nodes.Count > 0) { meshes.Add(CrcTool.FlModelCrc(vmsNode.Name), new VMeshData(vmsNode.Nodes[0].Data)); } } break; case "cmpnd": foreach (UTFNode cmpndNode in node.Nodes) { if (cmpndNode.Name.Equals("cons", StringComparison.OrdinalIgnoreCase)) { foreach (UTFNode constructNode in cmpndNode.Nodes) { switch (constructNode.Name.ToLowerInvariant()) { case "fix": FixConstruct.Parse(constructs, constructNode.Data); break; case "rev": RevConstruct.Parse(constructs, constructNode.Data); break; case "pris": PrisConstruct.Parse(constructs, constructNode.Data); break; case "sphere": SphereConstruct.Parse(constructs, constructNode.Data); break; } } } else if (cmpndNode.Name.StartsWith("part_", StringComparison.OrdinalIgnoreCase) || cmpndNode.Name.Equals("root", StringComparison.OrdinalIgnoreCase)) { string objectName = null; string fileName = null; //int index = -1; foreach (UTFNode partNode in cmpndNode.Nodes) { switch (partNode.Name.ToLowerInvariant()) { case "object name": objectName = Encoding.ASCII.GetString(partNode.Data).TrimEnd('\0'); break; case "file name": fileName = Encoding.ASCII.GetString(partNode.Data).TrimEnd('\0'); break; //case "index": // index = BitConverter.ToInt32(partNode.Data, 0); // break; } } if (objectName != null && fileName != null) { mapFileToObj[fileName] = objectName; } } } break; case "multilevel": // multi LoD 3db model (\MultiLevel\Level0\VMeshPart\VMeshRef => \) VMeshRef meshReference2 = ParseMultiLevelNode(node); if (meshReference2 != null) { meshReferenceNodes.Add(new MeshReferenceMatch { FileName = "\\", MeshReference = meshReference2 }); } break; case "vmeshpart": // single LoD 3db model (\VMeshPart\VMeshRef => \) VMeshRef meshReference3 = ParseMeshPartNode(node); if (meshReference3 != null) { meshReferenceNodes.Add(new MeshReferenceMatch { FileName = "\\", MeshReference = meshReference3 }); } break; default: if (node.Name.EndsWith(".3db", StringComparison.OrdinalIgnoreCase)) { foreach (UTFNode subNode in node.Nodes) { if (subNode.Name.Equals("multilevel", StringComparison.OrdinalIgnoreCase)) { // multi LoD cmp model (\PARTNAME.3db\MultiLevel\Level0\VMeshPart\VMeshRef => PARTNAME.3db) VMeshRef meshReference = ParseMultiLevelNode(subNode); if (meshReference != null) { meshReferenceNodes.Add(new MeshReferenceMatch { FileName = node.Name, MeshReference = meshReference }); } break; } if (subNode.Name.Equals("vmeshpart", StringComparison.OrdinalIgnoreCase)) { // single LoD cmp model (\PARTNAME.3db\VMeshPart\VMeshRef => PARTNAME.3db) VMeshRef meshReference = ParseMeshPartNode(subNode); if (meshReference != null) { meshReferenceNodes.Add(new MeshReferenceMatch { FileName = node.Name, MeshReference = meshReference }); } break; } } } break; } } if (meshes == null || meshReferenceNodes.Count == 0) { return(null); } List <MeshGroup> meshGroups = new List <MeshGroup>(); foreach (MeshReferenceMatch meshReferenceNode in meshReferenceNodes) { string meshGroupName; if (mapFileToObj.TryGetValue(meshReferenceNode.FileName, out meshGroupName)) { VMeshData mesh; if (meshes.TryGetValue(meshReferenceNode.MeshReference.VMeshLibId, out mesh)) { meshGroups.Add(new MeshGroup { MeshReference = meshReferenceNode.MeshReference, Mesh = mesh, Transform = GetTransform(constructs, meshGroupName) }); } } } return(GetCmpModelGroup(meshGroups)); }