private void WriteFolderBlocks(BinaryWriterEx bw, FolderEntry folder) { var allChilds = folder.GetEntryHierarchy().ToList(); var totalFilesSize = allChilds.OfType <FileEntry>().Sum(x => x.FileSize); var folderBlock = new LIFFBlock { BlockHeader = 1, BlockType = 3, BlockSize = ((allChilds.Count() + 1) * LIFFBLOCK_SIZE) + (int)totalFilesSize }; bw.WriteStruct(folderBlock); foreach (var entry in folder.Entries.OrderBy(x => x.Name)) { if (entry is FileEntry file) { var fileBlock = new LIFFBlock { BlockHeader = 1, BlockType = 4, Spacing2 = 1, BlockSize = LIFFBLOCK_SIZE + (int)file.FileSize }; bw.WriteStruct(fileBlock); var fileStream = file.GetStream(); //fileStream.CopyTo(bw.BaseStream, 4096); byte[] buffer = new byte[4096]; int bytesRead = 0; while (bytesRead < file.FileSize) { int b = fileStream.Read(buffer, 0, buffer.Length); bytesRead += b; bw.Write(buffer, 0, b); if (b == 0) { break; } } } else { WriteFolderBlocks(bw, (FolderEntry)entry); } } }
public void WriteToStream(Stream stream) { if (stream == BaseStream) { throw new InvalidOperationException("Cannot overwrite the same stream."); } using (var bw = new BinaryWriterEx(stream, true)) { bw.DefaultEndian = Endianness.BigEndian; var header = LIFFHeader.Default; bw.WriteStruct(header); long rootBlockPos = stream.Position; var rootBlock = new LIFFBlock { BlockHeader = 1, BlockType = 1, }; bw.WriteStruct(rootBlock); var contentBlock = new LIFFBlock { BlockHeader = 1, BlockType = 2, Spacing2 = 1, BlockSize = 26 }; bw.WriteStruct(contentBlock); bw.WriteInt16(1); bw.WriteInt32(0); WriteFolderBlocks(bw, RootFolder); long hierarchyBlockPos = stream.Position; var hierarchyBlock = new LIFFBlock { BlockHeader = 1, BlockType = 5, Spacing2 = 1 }; bw.WriteStruct(hierarchyBlock); WriteFolderEntries(bw, RootFolder); hierarchyBlock.BlockSize = (int)(stream.Position - hierarchyBlockPos); stream.Position = hierarchyBlockPos; bw.WriteStruct(hierarchyBlock); rootBlock.BlockSize = (int)(stream.Length - rootBlockPos); stream.Position = rootBlockPos; bw.WriteStruct(rootBlock); header.FileSize = (int)stream.Length; stream.Position = 0; bw.WriteStruct(header); } }
private void WriteFolderEntries(BinaryWriterEx bw, FolderEntry folder) { var allChilds = folder.GetEntryHierarchy().ToList(); var folderEntry = new LIFFFolderEntry() { EntryType = 1, Filename = folder.IsRootDirectory ? null : folder.Name, EntryCount = folder.Entries.Count, Reserved1 = folder.IsRootDirectory ? 0 : 7, BlockSize = 20 }; bw.WriteStruct(folderEntry); foreach (var entry in folder.Entries.OrderBy(x => x.Name)) { if (entry is FileEntry file) { var fileEntry = new LIFFFileEntry() { EntryType = 2, Filename = file.Name, FileSize = (int)file.FileSize + LIFFBLOCK_SIZE, Reserved1 = 7, Created = file.CreatedDate.ToFileTime(), Modified = file.ModifiedDate.ToFileTime(), Accessed = file.AccessedDate.ToFileTime() }; bw.WriteStruct(fileEntry); } else { WriteFolderEntries(bw, (FolderEntry)entry); } } }
public static void WriteMeshFile(Stream stream, MESH_FILE meshFile) { using (var bw = new BinaryWriterEx(stream, Encoding.UTF8, true)) { bw.WriteStruct(meshFile.Header); void WriteVector3(Vector3 v) { bw.WriteSingle(v.X); bw.WriteSingle(v.Y); bw.WriteSingle(v.Z); } void WriteVector2(Vector2 v) { bw.WriteSingle(v.X); bw.WriteSingle(v.Y); } foreach (var pos in meshFile.Geometry.Positions) { WriteVector3(pos); } foreach (var norm in meshFile.Geometry.Normals) { WriteVector3(norm); } if (meshFile.Geometry.UVs != null && meshFile.Geometry.UVs.Length > 0) { foreach (var uv in meshFile.Geometry.UVs) { WriteVector2(uv); } } for (int i = 0; i < meshFile.Header.IndexCount; i++) { bw.WriteInt32(meshFile.Geometry.Indices[i].VertexIndex); } //Round Edge Shader Data { var allShaderData = meshFile.RoundEdgeShaderData.SelectMany(x => x.Coords).ToList(); bw.WriteInt32(allShaderData.Count * 2); foreach (var shaderCoord in allShaderData) { WriteVector2(shaderCoord); } for (int i = 0; i < meshFile.Header.IndexCount; i++) { bw.WriteInt32(meshFile.Geometry.Indices[i].REShaderOffset); } } //Average Normals { bw.WriteInt32(meshFile.AverageNormals.Length + 1); WriteVector3(new Vector3(83, 0, 0)); foreach (var avgNorm in meshFile.AverageNormals) { WriteVector3(avgNorm); } for (int i = 0; i < meshFile.Header.IndexCount; i++) { bw.WriteInt32(meshFile.Geometry.Indices[i].AverageNormalIndex); } } if (meshFile.Geometry.Bones != null && meshFile.Geometry.Bones.Length > 0) { //TODO: If flexible alternate meshes are supported, improve this code to include alternate meshes bones // and a way to retrieve the correct offsets in WriteCullingInfo var allBones = meshFile.Geometry.Bones.SelectMany(x => x.BoneWeights).ToList(); int boneDataSize = (allBones.Count * 8) + (meshFile.Header.VertexCount * 4); bw.WriteInt32(boneDataSize); var dataOffsets = new List <int>(); int totalOffset = 0; for (int i = 0; i < meshFile.Header.VertexCount; i++) { var vertexBones = meshFile.Geometry.Bones[i]; bw.WriteInt32(vertexBones.BoneWeights.Length); for (int j = 0; j < vertexBones.BoneWeights.Length; j++) { bw.WriteInt32(vertexBones.BoneWeights[j].BoneID); bw.WriteSingle(vertexBones.BoneWeights[j].Weight); } //bone count (4 bytes) + bones data (id + weight = 8 bytes) dataOffsets.Add(totalOffset); totalOffset += 4 + (vertexBones.BoneWeights.Length * 8); } for (int i = 0; i < meshFile.Header.VertexCount; i++) { bw.WriteInt32(dataOffsets[i]); } } //Mesh Culling Info { bw.WriteInt32(meshFile.Cullings.Length); WriteSizedBlock(bw, () => { for (int i = 0; i < meshFile.Cullings.Length; i++) { WriteCullingInfo(bw, meshFile.Cullings[i]); } }, false); } } }