public void Draw(string path, Matrix3D?parentMatrix = null) { ESO eso; do { var matrix = GetMatrix(eso = ESO.FromFile(path)); if (parentMatrix.HasValue) { matrix *= parentMatrix.Value; } foreach (var model in eso.Models) { BitmapImage image; var material = new DiffuseMaterial(Brushes.White); var geom = new MeshGeometry3D { Positions = new Point3DCollection(model.Vertices.Select(AssetHelper.ConvertVertex)), Normals = new Vector3DCollection(model.Normals.Select(AssetHelper.ConvertVector)) }; var ema = EMA.FromFile(Path.Combine(MainWindow.Edge.ModelsDirectory, model.MaterialAsset + ".ema")); if (ema.Textures.Length > 0 && model.HasTexCoords) { geom.TextureCoordinates = new PointCollection(model.TexCoords.Select(ConvertTexCoord)); var etx = ETX.FromFile(Path.Combine(MainWindow.Edge.TexturesDirectory, ema.Textures[0].Asset + ".etx")); image = etx.GetBitmap().GetBitmapImage(); Viewport2DVisual3D.SetIsVisualHostMaterial(material, true); } else { image = new BitmapImage(); } if (!parentMatrix.HasValue && model.HasColors) { TaskDialog.Show(this, Localization.Warning, Localization.ModelColorWarning, Localization.ModelColorWarningDetails, TaskDialogType.Warning); } for (var i = model.Vertices.Count - 1; i >= 0; i--) { geom.TriangleIndices.Add(i); } var transform = new MatrixTransform3D(matrix); Model.Children.Add(new Viewport2DVisual3D { Geometry = geom, Material = material, Visual = new Image { Source = image }, Transform = transform }); if (!DebugMode) { continue; } var lines = new ScreenSpaceLines3D { Color = Colors.Red, Transform = transform }; Model.Children.Add(lines); var k = 0; while (k < model.Vertices.Count) { lines.Points.Add(AssetHelper.ConvertVertex(model.Vertices[k])); lines.Points.Add(AssetHelper.ConvertVertex(model.Vertices[k + 1])); lines.Points.Add(AssetHelper.ConvertVertex(model.Vertices[k + 1])); lines.Points.Add(AssetHelper.ConvertVertex(model.Vertices[k + 2])); lines.Points.Add(AssetHelper.ConvertVertex(model.Vertices[k + 2])); lines.Points.Add(AssetHelper.ConvertVertex(model.Vertices[k])); k += 3; } } if (!DrawChildModels) { return; } if (!eso.Header.NodeChild.IsZero()) { Draw(Path.Combine(Path.GetDirectoryName(path), eso.Header.NodeChild + ".eso"), matrix); } path = Path.Combine(Path.GetDirectoryName(path), eso.Header.NodeSibling + ".eso"); }while (!eso.Header.NodeSibling.IsZero()); }
public static Tuple <Exception, string, List <FileEntry> > Compile(bool exFormat, string file, string directory = null) { var list = new List <FileEntry>(); var fileName = Path.GetFileNameWithoutExtension(file); if (string.IsNullOrWhiteSpace(directory)) { directory = Path.GetDirectoryName(file); } string inputPath = Path.Combine(Path.GetDirectoryName(file), fileName), outputPath = Path.Combine(directory, fileName); Warning.Start(); try { switch ((Path.GetExtension(file) ?? string.Empty).ToLowerInvariant()) { case ".bin": switch (fileName.ToLowerInvariant()) { case "cos": var array = new short[181]; using (var stream = File.OpenRead(file)) using (var reader = new BinaryReader(stream)) for (var i = 0; i <= 180; i++) { array[i] = reader.ReadInt16(); } File.WriteAllText(outputPath += ".txt", string.Join(Environment.NewLine, array.Select(value => value / 256.0))); list.Add(new FileEntry(outputPath, "cos.txt")); break; case "font": DecompileFont(file, ref outputPath); list.Add(new FileEntry(outputPath, "font.xml")); break; default: { var index = 0; foreach (var path in Level.CreateFromCompiled(file).Decompile(outputPath)) { list.Add(new FileEntry(path, index == 0 ? "level.xml" : index == 1 ? "level.png" : "level.z.png")); index++; } break; } } break; case ".xml": var root = XHelper.Load(file).Elements().First(); switch (root.Name.LocalName.ToLowerInvariant()) { case "level": { var index = 0; foreach (var path in Level.CreateFromDecompiled(inputPath) .Compile(outputPath + ".bin")) { list.Add(new FileEntry(path, index == 0 ? "level.bin" : "model.eso")); index++; } break; } case "animation": AssetHelper.ParseEan(root, fileName).Save(outputPath = Path.Combine(directory, AssetUtil.CrcFullName(fileName, "models") + ".ean")); list.Add(new FileEntry(outputPath, "animation.ean")); break; case "material": { string name; Helper.AnalyzeFileName(out name, out outputPath, fileName); var ema = AssetHelper.ParseEma(root, name); ema.Save(Path.Combine(directory, outputPath += ".ema")); list.Add(new FileEntry(outputPath, "material.ema")); break; } case "models": { string name; Helper.AnalyzeFileName(out name, out outputPath, fileName); var eso = AssetHelper.ParseEso(root, name); eso.Save(Path.Combine(directory, outputPath += ".eso")); list.Add(new FileEntry(outputPath, "model.eso")); break; } case "font": { CompileFont(inputPath, out outputPath, root); list.Add(new FileEntry(outputPath, "font.bin")); break; } } break; case ".loc": LOC.FromFile(file).SaveXls(outputPath += ".xls"); list.Add(new FileEntry(outputPath, "text.xls")); break; case ".xls": LocHelper.FromXls(file).Save(outputPath += ".loc"); list.Add(new FileEntry(outputPath, "text.loc")); break; case ".etx": var etx = ETX.FromFile(file); etx.GetBitmap().Save(outputPath = Path.Combine(directory, etx.AssetHeader.Name + ".png")); list.Add(new FileEntry(outputPath, "texture.png")); break; case ".png": { var name = AssetUtil.CrcFullName(fileName, "textures") + ".etx"; (exFormat ? (ETX)ETX1804.CreateFromImage(file) : ETX1803.CreateFromImage(file)) .Save(outputPath = Path.Combine(directory, name)); list.Add(new FileEntry(outputPath, "texture.etx")); break; } case ".ean": var ean = EAN.FromFile(file); File.WriteAllText(outputPath = Path.Combine(directory, Helper.GetDecompiledFileName(fileName, ean) + ".xml"), AssetHelper.GetEanElement(ean).ToString()); list.Add(new FileEntry(outputPath, "animation.xml")); break; case ".ema": { var ema = EMA.FromFile(file); File.WriteAllText(outputPath = Path.Combine(directory, Helper.GetDecompiledFileName(fileName, ema) + ".xml"), AssetHelper.GetEmaElement(ema).ToString()); list.Add(new FileEntry(outputPath, "material.xml")); break; } case ".eso": { var eso = ESO.FromFile(file); File.WriteAllText(outputPath = Path.Combine(directory, Helper.GetDecompiledFileName(fileName, eso) + ".xml"), AssetHelper.GetEsoElement(eso).ToString()); list.Add(new FileEntry(outputPath, "model.xml")); break; } case ".txt": using (var stream = new FileStream(outputPath += ".bin", FileMode.Create, FileAccess.Write, FileShare.Read)) { var writer = new BinaryWriter(stream); foreach (var num in File.ReadAllText(file) .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(double.Parse)) { writer.Write((short)Math.Round(num * 256)); } } list.Add(new FileEntry(outputPath, "cos.bin")); break; default: switch (Path.GetFileName(file)) { case "audio": if (Directory.Exists(outputPath = Path.Combine(directory, "sfx"))) { Directory.Delete(outputPath, true); } Directory.CreateDirectory(outputPath); string xsb = Path.Combine(file, "sfx.xsb"), xwb = Path.Combine(file, "sfx.xwb"); int offset; using (var stream = new FileStream(xsb, FileMode.Open)) { stream.Position = 0x2A; using (var reader = new BinaryReader(stream)) offset = reader.ReadInt32(); } var unxwb = new Process { StartInfo = new ProcessStartInfo( Path.Combine(CurrentApp.Directory, "Resources/Libraries/unxwb.exe"), FormattableString.Invariant($"-d \"{outputPath}\" -b \"{xsb}\" {offset} \"{xwb}\"")) { UseShellExecute = false, CreateNoWindow = true } }; unxwb.Start(); unxwb.WaitForExit(); list.Add(new FileEntry(outputPath, "sfx")); break; case "sfx": Directory.CreateDirectory(outputPath = Path.Combine(directory, "audio")); string tempPath = Helper.GetRandomDirectory(), tempInputPath = Path.Combine(tempPath, "sfx"), tempOutputPath = Path.Combine(tempPath, "audio"); /************************************************************************************ * create temp input dir because it's still occupied for unknown reason; * * create temp output dir because COMException will be thrown if output dir and * * temp input dir is not under the same drive. * ************************************************************************************/ Directory.CreateDirectory(tempInputPath); var projectPath = GenerateXactProject(file, tempInputPath); using (var project = new CXACTMasterProject()) { project.Create(); project.Load(projectPath, new CXACTMasterProjectCallback(), 0); project.Build(new CXACTMasterProjectCallback(), tempOutputPath, false, false); } foreach (var path in Directory.EnumerateFiles(tempOutputPath)) { var target = Path.Combine(outputPath, Path.GetFileName(path)); File.Delete(target); File.Move(path, target); } try { Directory.Delete(tempPath, true); } catch { Trace.WriteLine(tempPath, "Delete tempPath failed"); } list.Add(new FileEntry(outputPath, "audio")); break; default: throw new NotSupportedException(Localization.DecompileUnrecognizedFile); } break; } return(new Tuple <Exception, string, List <FileEntry> >(null, Warning.Fetch(), list)); } catch (Exception exc) { return(new Tuple <Exception, string, List <FileEntry> >(exc, Warning.Fetch(), list)); } finally { Warning.Clear(); } }