예제 #1
0
            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);
            }
        }
예제 #3
0
        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}");
             * }*/
        }