public IFile SaveInDirectory(IDirectory directory) { var outFile = new FinFile(Path.Combine(directory.FullName, this.Name + ".png")); using var writer = outFile.OpenWrite(); this.Image.ExportToStream(writer, LocalImageFormat.PNG); return(outFile); }
public void Process( IDirectory outputDirectory, IList <string> bmdPaths, IList <string> bcxPaths, IList <string> btiPaths, bool wasSourcedAutomatically = false, float frameRate = 30) { var logger = Logging.Create <ManualBmd2FbxApi>(); logger.LogInformation("Attempting to parse:"); logger.LogInformation( $"- {bmdPaths.Count} model(s):\n" + string.Join('\n', bmdPaths.Select(bmdPath => " " + bmdPath))); logger.LogInformation( $"- {bcxPaths.Count} animation(s):\n" + string.Join('\n', bcxPaths.Select(bcxPath => " " + bcxPath))); logger.LogInformation( $"- {btiPaths.Count} external texture(s):\n" + string.Join('\n', btiPaths.Select(btiPath => " " + btiPath))); logger.LogInformation(" "); Asserts.True( !wasSourcedAutomatically || (bmdPaths.Count == 1 || !bcxPaths.Any()), "While automatically gathering files for a directory, found " + "multiple BMDs and animations. Not sure which animations go with " + "which BMDs, so aborting this operation."); var nonexistentBmds = bmdPaths.Where(bmdPath => !File.Exists(bmdPath)); var bmdsExist = !nonexistentBmds.Any(); if (!bmdsExist) { throw new ArgumentException("Some bmds don't exist: " + string.Join(' ', nonexistentBmds)); } var nonexistentBcxes = bcxPaths.Where(bcxPath => !File.Exists(bcxPath)); var bcxesExist = !nonexistentBcxes.Any(); if (!bcxesExist) { throw new ArgumentException("Some bcxes don't exist: " + string.Join(' ', nonexistentBcxes)); } var nonexistentBtis = btiPaths.Where(btiPath => !File.Exists(btiPath)); var btisExist = !nonexistentBtis.Any(); if (!btisExist) { throw new ArgumentException("Some btis don't exist: " + string.Join(' ', nonexistentBtis)); } outputDirectory.Create(); /*foreach (var bmdPath in bmdPaths) { * var bmdFile = new FileInfo(bmdPath); * BmdDebugHelper.ExportFilesInBmd(outputDirectory, * bmd, * bmdFile.Name.Substring( * 0, * bmdFile.Name.Length - * ".bmd".Length), * pathsAndBtis); * }*/ foreach (var bmdPath in bmdPaths) { var bmdFile = new FinFile(bmdPath); var model = new BmdModelLoader() .LoadModel(new BmdModelFileBundle { BmdFile = bmdFile, BcxFiles = bcxPaths .Select(bcxPath => new FinFile(bcxPath)) .ToArray(), BtiFiles = btiPaths .Select(btiPath => new FinFile(btiPath)) .ToArray(), FrameRate = frameRate }); new AssimpIndirectExporter().Export( new FinFile(Path.Join(outputDirectory.FullName, bmdFile.Name)) .CloneWithExtension(".fbx"), model); } }
public void Run(string scratchDirectoryPath, string outputDirectoryPath) { string gameDirectory = null; if (OperatingSystem.IsWindows()) { gameDirectory = SteamInterop.GetGameInstallDirectory("HaloWarsDE"); Console.WriteLine( $"Found Halo Wars Definitive Edition install at {gameDirectory}"); } // Point the framework to the game install and working directories var context = new HWContext(gameDirectory, scratchDirectoryPath); // Expand all compressed/encrypted game files. This also handles the .xmb -> .xml conversion context.ExpandAllEraFiles(); var scratchDirectory = new FinDirectory(scratchDirectoryPath); var mapDirectories = scratchDirectory .GetSubdir("scenario/skirmish/design") .GetExistingSubdirs(); var outputDirectory = new FinDirectory(outputDirectoryPath); var baseDstMapDirectory = outputDirectory.GetSubdir("scenario/skirmish/design", true); foreach (var srcMapDirectory in mapDirectories) { var mapName = srcMapDirectory.Name; var dstMapDirectory = baseDstMapDirectory.GetSubdir(mapName, true); var gltfFile = new FinFile( Path.Combine(dstMapDirectory.FullName, $"{mapName}.gltf")); if (gltfFile.Exists) { continue; } var xttFile = srcMapDirectory.GetExistingFiles() .Single(file => file.Extension == ".xtt"); var xtdFile = srcMapDirectory.GetExistingFiles() .Single(file => file.Extension == ".xtd"); var xtt = HWXttResource.FromFile(context, xttFile.FullName); var xtd = HWXtdResource.FromFile(context, xtdFile.FullName); var finModel = xtd.Mesh; var xttMaterial = finModel.MaterialManager.AddStandardMaterial(); xttMaterial.DiffuseTexture = finModel.MaterialManager.CreateTexture( xtt.AlbedoTexture); xttMaterial.DiffuseTexture.Name = $"{mapName}_albedo"; xttMaterial.AmbientOcclusionTexture = finModel.MaterialManager.CreateTexture( xtd.AmbientOcclusionTexture); xttMaterial.AmbientOcclusionTexture.Name = $"{mapName}_ao"; foreach (var primitive in finModel.Skin.Meshes[0].Primitives) { primitive.SetMaterial(xttMaterial); } var exporter = new AssimpIndirectExporter { LowLevel = true }; exporter.Export(gltfFile.CloneWithExtension(".fbx"), finModel); // Cleans up any remaining .bin files. var binFiles = dstMapDirectory.GetExistingFiles() .Where(file => file.Extension == ".bin"); foreach (var binFile in binFiles) { binFile.Info.Delete(); } // Forces an immediate garbage-collection cleanup. This is required to // prevent OOM errors, since Halo Wars maps are just so huge. GC.Collect(); GC.WaitForFullGCComplete(); GC.WaitForPendingFinalizers(); } var artDirectory = scratchDirectory.GetSubdir("art"); var artSubdirQueue = new FinQueue <IDirectory>(artDirectory); // TODO: Switch to DFS instead, it's more intuitive as a user while (artSubdirQueue.TryDequeue(out var artSubdir)) { // TODO: Skip a file if it's already been extracted // TODO: Parse UGX files instead, as long as they specify their own animations var visFiles = artSubdir.GetExistingFiles() .Where(f => f.Extension == ".vis") .ToList(); foreach (var visFile in visFiles) { var vis = HWVisResource.FromFile(context, visFile.FullName); var finModel = vis.Model; var outFilePath = visFile.FullName.Replace(scratchDirectoryPath, outputDirectoryPath); var outFile = new FinFile(outFilePath).CloneWithExtension(".fbx"); outFile.GetParent().Create(); var exporter = new AssimpIndirectExporter(); exporter.Export(outFile, finModel); Console.WriteLine($"Processed {visFile.FullName}"); } artSubdirQueue.Enqueue(artSubdir.GetExistingSubdirs()); } /*var gls = HWGlsResource.FromFile(context, * "scenario\\skirmish\\design\\blood_gulch\\blood_gulch.gls"); * Console.WriteLine($"Processed {gls}"); * * var scn = HWScnResource.FromFile(context, * "scenario\\skirmish\\design\\blood_gulch\\blood_gulch.scn"); * PrintScenarioObjects(scn); * Console.WriteLine($"Processed {scn}"); * * var sc2 = HWSc2Resource.FromFile(context, * "scenario\\skirmish\\design\\blood_gulch\\blood_gulch.sc2"); * PrintScenarioObjects(sc2); * Console.WriteLine($"Processed {sc2}"); * * var sc3 = HWSc3Resource.FromFile(context, * "scenario\\skirmish\\design\\blood_gulch\\blood_gulch.sc3"); * PrintScenarioObjects(sc3); * Console.WriteLine($"Processed {sc3}"); * }*/ }