source: OniSplit/Program.cs

Last change on this file was 1154, checked in by geyser, 4 years ago

Implemented import/export of "fact" chunk for .wav files. Added a -demo tag for storing sounds in the PC demo format (if compatible).

File size: 34.1 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Reflection;
5using Oni.Akira;
6using Oni.Collections;
7using Oni.Metadata;
8using Oni.Sound;
9using Oni.Xml;
10
11namespace Oni
12{
13 internal class Program
14 {
15 private static readonly InstanceFileManager fileManager = new InstanceFileManager();
16
17 private static int Main(string[] args)
18 {
19 if (args.Length == 0)
20 {
21 Help(args);
22 Console.WriteLine("Press any key to continue");
23 Console.ReadKey();
24 return 0;
25 }
26
27 if (args[0] == "-cdump")
28 {
29 InstanceMetadata.DumpCStructs(Console.Out);
30 return 0;
31 }
32
33 Dae.IO.DaeReader.CommandLineArgs = args;
34
35 if (args[0] == "-silent")
36 {
37 Console.SetOut(new StreamWriter(Stream.Null));
38 Console.SetError(new StreamWriter(Stream.Null));
39
40 var newArgs = new string[args.Length - 1];
41 Array.Copy(args, 1, newArgs, 0, newArgs.Length);
42 args = newArgs;
43 }
44
45 if (args[0] == "-noexcept")
46 {
47 var newArgs = new string[args.Length - 1];
48 Array.Copy(args, 1, newArgs, 0, newArgs.Length);
49 args = newArgs;
50 return Execute(args);
51 }
52
53 args = AddSearchPaths(args);
54
55 try
56 {
57 return Execute(args);
58 }
59 catch (Exception ex)
60 {
61 Console.Error.WriteLine(ex.ToString());
62 return 1;
63 }
64 }
65
66 private static int Execute(string[] args)
67 {
68 if (args[0].StartsWith("-export:", StringComparison.Ordinal))
69 return Unpack(args);
70
71 switch (args[0])
72 {
73 case "-help":
74 return Help(args);
75
76 case "-version":
77 return PrintVersion();
78
79 case "-export":
80 return Unpack(args);
81
82 case "pack":
83 case "-import":
84 case "-import:nosep":
85 case "-import:sep":
86 case "-import:ppc":
87 case "-import:pc":
88 return Pack(args);
89
90 case "-copy":
91 return Copy(args);
92
93 case "-move":
94 case "-move:overwrite":
95 case "-move:delete":
96 return Move(args);
97
98 case "-list":
99 return List(args);
100
101 case "-deps":
102 return GetDependencies(args);
103
104 case "extract":
105 case "-extract:xml":
106 return ExportXml(args);
107
108 case "-extract:tga":
109 case "-extract:dds":
110 case "-extract:png":
111 case "-extract:jpg":
112 case "-extract:bmp":
113 case "-extract:tif":
114 return ExportTextures(args);
115
116 case "-extract:wav":
117 case "-extract:aif":
118 case "-extract:pcm":
119 return ExportSounds(args);
120
121 case "-extract:obj":
122 case "-extract:dae":
123 return ExportGeometry(args);
124
125 case "-extract:txt":
126 return ExportSubtitles(args);
127
128 case "-create:akev":
129 return CreateAkira(args);
130
131 case "-create:tram":
132 case "-create:trbs":
133 case "-create:txmp":
134 case "-create:m3gm":
135 case "-create:subt":
136 case "-create:oban":
137 case "-create":
138 case "create":
139 return CreateGeneric(args);
140
141 case "-grid:create":
142 return CreateGrids(args);
143
144 case "-create:level":
145 return ImportLevel(args);
146
147 case "-room:extract":
148 return ExtractRooms(args);
149
150 case "film2xml":
151 return ConvertFilm2Xml(args);
152
153 default:
154 Console.Error.WriteLine("Unknown command {0}", args[0]);
155 return 1;
156 }
157 }
158
159 private static string[] AddSearchPaths(string[] args)
160 {
161 List<string> newArgs = new List<string>();
162
163 for (int i = 0; i < args.Length; i++)
164 {
165 if (args[i] == "-search")
166 {
167 i++;
168
169 if (i < args.Length)
170 fileManager.AddSearchPath(args[i]);
171 }
172 else
173 {
174 newArgs.Add(args[i]);
175 }
176 }
177
178 return newArgs.ToArray();
179 }
180
181 private static int Help(string[] args)
182 {
183 if (args.Length > 1 && args[1] == "enums")
184 {
185 HelpEnums();
186 return 0;
187 }
188
189 Console.WriteLine("{0} [options] datfile", Environment.GetCommandLineArgs()[0]);
190 Console.WriteLine();
191 Console.WriteLine("Options:");
192 Console.WriteLine("\t-export <directory>\t\tExport a Oni .dat file to directory");
193 Console.WriteLine("\t-import <directory>\t\tImport a Oni .dat file from directory");
194 Console.WriteLine("\t\t\t\t\tTarget file format is determined from source files (when possible)");
195 Console.WriteLine("\t-import:sep <directory>\t\tImport a Oni .dat file from directory");
196 Console.WriteLine("\t\t\t\t\tCreate a .dat file that uses .raw and .sep binary files (Mac and PC Demo)");
197 Console.WriteLine("\t-import:nosep <directory>\tImport a Oni .dat file from directory");
198 Console.WriteLine("\t\t\t\t\tCreate a .dat file that uses only .raw binary file (PC)");
199 Console.WriteLine();
200 Console.WriteLine("\t-extract:dds <directory>\tExtracts all textures (TXMP) from a Oni .dat/.oni file in DDS format");
201 Console.WriteLine("\t-extract:tga <directory>\tExtracts all textures (TXMP) from a Oni .dat/.oni file in TGA format");
202 Console.WriteLine("\t-extract:png <directory>\tExtracts all textures (TXMP) from a Oni .dat/.oni file in PNG format");
203 Console.WriteLine("\t-extract:wav <directory>\tExtracts all sounds (SNDD) from a Oni .dat/.oni file in WAV format");
204 Console.WriteLine("\t-extract:aif <directory>\tExtracts all sounds (SNDD) from a Oni .dat/.oni file in AIF format");
205 Console.WriteLine("\t-extract:txt <directory>\tExtracts all subtitles (SUBT) from a Oni .dat/.oni file in TXT format");
206 Console.WriteLine("\t-extract:obj <directory>\tExtracts all M3GM and ONCC instances to Wavefront OBJ files");
207 Console.WriteLine("\t-extract:dae <directory>\tExtracts all M3GM and ONCC instances to Collada files");
208 Console.WriteLine("\t-extract:xml <directory>\tExtracts all instances to XML files");
209 Console.WriteLine();
210 Console.WriteLine("\t-create:txmp <directory> [-nomipmaps] [-nouwrap] [-novwrap] [-format:bgr|rgba|bgr555|bgra5551|bgra4444|dxt1] [-envmap:texture_name] [-large] image_file");
211 Console.WriteLine("\t-create:m3gm <directory> [-tex:texture_name] obj_file");
212 Console.WriteLine("\t-create:trbs <directory> dae_file");
213 Console.WriteLine("\t-create:subt <directory> txt_file");
214 Console.WriteLine("\t-create <directory> xml_file\tCreates an .oni file from an XML file");
215 Console.WriteLine();
216 Console.WriteLine("\t-grid:create -out:<directory> rooms_src.dae level_geometry1.dae level_geometry2.dae ...\tGenerates pathfinding grids");
217 Console.WriteLine();
218 Console.WriteLine("\t-list\t\t\t\tLists the named instances contained in datfile");
219 Console.WriteLine("\t-copy <directory>\t\tCopy an exported .oni file and its dependencies to directory");
220 Console.WriteLine("\t-move <directory>\t\tMove an exported .oni file and its dependencies to directory");
221 Console.WriteLine("\t-move:overwrite <directory>\tMove an exported .oni file and its dependencies to directory");
222 Console.WriteLine("\t\t\t\t\tOverwrites any existing files");
223 Console.WriteLine("\t-move:delete <directory>\tMove an exported .oni file and its dependencies to directory");
224 Console.WriteLine("\t\t\t\t\tDeletes files at source when they already exist at destination");
225 Console.WriteLine("\t-deps\t\t\t\tGet a list of exported .oni files the specified files depends on");
226 Console.WriteLine("\t-version\t\t\tShow OniSplit versions");
227 Console.WriteLine("\t-help\t\t\t\tShow this help");
228 Console.WriteLine("\t-help enums\t\t\tShow a list of enums and flags used in XML files");
229 Console.WriteLine();
230
231 return 0;
232 }
233
234 private static void HelpEnums()
235 {
236 WriteEnums(typeof(InstanceMetadata));
237 WriteEnums(typeof(ObjectMetadata));
238
239 Console.WriteLine("-----------------------------------------------------");
240 Console.WriteLine("Particles enums");
241 Console.WriteLine("-----------------------------------------------------");
242 Console.WriteLine();
243
244 Utils.WriteEnum(typeof(Particles.ParticleFlags1));
245 Utils.WriteEnum(typeof(Particles.ParticleFlags2));
246 Utils.WriteEnum(typeof(Particles.EmitterFlags));
247 Utils.WriteEnum(typeof(Particles.EmitterOrientation));
248 Utils.WriteEnum(typeof(Particles.EmitterPosition));
249 Utils.WriteEnum(typeof(Particles.EmitterRate));
250 Utils.WriteEnum(typeof(Particles.EmitterSpeed));
251 Utils.WriteEnum(typeof(Particles.EmitterDirection));
252 Utils.WriteEnum(typeof(Particles.DisableDetailLevel));
253 Utils.WriteEnum(typeof(Particles.AttractorSelector));
254 Utils.WriteEnum(typeof(Particles.AttractorTarget));
255 Utils.WriteEnum(typeof(Particles.EventType));
256 Utils.WriteEnum(typeof(Particles.SpriteType));
257 Utils.WriteEnum(typeof(Particles.StorageType));
258 Utils.WriteEnum(typeof(Particles.ValueType));
259
260 Console.WriteLine("-----------------------------------------------------");
261 Console.WriteLine("Object enums");
262 Console.WriteLine("-----------------------------------------------------");
263 Console.WriteLine();
264
265 Utils.WriteEnum(typeof(Physics.ObjectSetupFlags));
266 Utils.WriteEnum(typeof(Physics.ObjectPhysicsType));
267 Utils.WriteEnum(typeof(Physics.ObjectAnimationFlags));
268 }
269
270 private static void WriteEnums(Type type)
271 {
272#if !NETCORE
273 foreach (var enumType in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
274 {
275 if (!enumType.IsEnum)
276 continue;
277
278 Utils.WriteEnum(enumType);
279 }
280#endif
281 }
282
283 private static int Unpack(string[] args)
284 {
285 if (args.Length < 3)
286 {
287 Console.Error.WriteLine("Invalid command line.");
288 return 1;
289 }
290
291 var prefixes = new List<string>();
292 string outputDirPath = null;
293 string sourceFilePath = null;
294
295 foreach (string arg in args)
296 {
297 if (arg.StartsWith("-export", StringComparison.Ordinal))
298 {
299 string prefix = null;
300 int i = arg.IndexOf(':');
301
302 if (i != -1)
303 prefix = arg.Substring(i + 1);
304
305 if (!string.IsNullOrEmpty(prefix))
306 prefixes.Add(prefix);
307 }
308 else if (outputDirPath == null)
309 {
310 outputDirPath = Path.GetFullPath(arg);
311 }
312 else if (sourceFilePath == null)
313 {
314 sourceFilePath = Path.GetFullPath(arg);
315 }
316 }
317
318 var unpacker = new DatUnpacker(fileManager, outputDirPath);
319
320 if (prefixes.Count > 0)
321 unpacker.NameFilter = Utils.WildcardToRegex(prefixes);
322
323 unpacker.ExportFiles(new[] { sourceFilePath });
324
325 return 0;
326 }
327
328 private static int ExportTextures(string[] args)
329 {
330 if (args.Length < 3)
331 {
332 Console.Error.WriteLine("Invalid command line.");
333 return 1;
334 }
335
336 int i = args[0].IndexOf(':');
337 string fileType = null;
338
339 if (i != -1)
340 fileType = args[0].Substring(i + 1);
341
342 var outputDirPath = Path.GetFullPath(args[1]);
343 var sourceFilePaths = GetFileList(args, 2);
344
345 var exporter = new Oni.Motoko.TextureExporter(fileManager, outputDirPath, fileType);
346 exporter.ExportFiles(sourceFilePaths);
347
348 return 0;
349 }
350
351 private static int ExportSounds(string[] args)
352 {
353 if (args.Length < 3)
354 {
355 Console.Error.WriteLine("Invalid command line.");
356 return 1;
357 }
358
359 int i = args[0].IndexOf(':');
360 string fileType = null;
361
362 if (i != -1)
363 fileType = args[0].Substring(i + 1);
364
365 var outputDirPath = Path.GetFullPath(args[1]);
366 var sourceFilePaths = GetFileList(args, 2);
367
368 SoundExporter exporter;
369 var noDemo = args.Any(a => a == "-nodemo");
370
371 switch (fileType)
372 {
373 case "aif":
374 exporter = new AifExporter(fileManager, outputDirPath, noDemo);
375 break;
376 case "wav":
377 exporter = new WavExporter(fileManager, outputDirPath, false, noDemo);
378 break;
379 case "pcm":
380 exporter = new WavExporter(fileManager, outputDirPath, true, noDemo);
381 break;
382 default:
383 throw new NotSupportedException(string.Format("Unsupported file type {0}", fileType));
384 }
385
386 exporter.ExportFiles(sourceFilePaths);
387
388 return 0;
389 }
390
391 private static int ExportGeometry(string[] args)
392 {
393 if (args.Length < 3)
394 {
395 Console.Error.WriteLine("Invalid command line.");
396 return 1;
397 }
398
399 int i = args[0].IndexOf(':');
400 string fileType = null;
401
402 if (i != -1)
403 fileType = args[0].Substring(i + 1);
404
405 var outputDirPath = Path.GetFullPath(args[1]);
406 var sourceFilePaths = GetFileList(args, 2);
407
408 var exporter = new DaeExporter(args, fileManager, outputDirPath, fileType);
409 exporter.ExportFiles(sourceFilePaths);
410
411 return 0;
412 }
413
414 private static int ExportSubtitles(string[] args)
415 {
416 if (args.Length < 3)
417 {
418 Console.Error.WriteLine("Invalid command line.");
419 return 1;
420 }
421
422 var outputDirPath = Path.GetFullPath(args[1]);
423 var sourceFilePaths = GetFileList(args, 2);
424
425 var exporter = new SubtitleExporter(fileManager, outputDirPath);
426 exporter.ExportFiles(sourceFilePaths);
427
428 return 0;
429 }
430
431 private static int ExportXml(string[] args)
432 {
433 if (args.Length < 3)
434 {
435 Console.Error.WriteLine("Invalid command line.");
436 return 1;
437 }
438
439 var outputDirPath = Path.GetFullPath(args[1]);
440 var sourceFilePaths = GetFileList(args, 2);
441
442 var exporter = new XmlExporter(fileManager, outputDirPath)
443 {
444 Recursive = args.Any(a => a == "-recurse"),
445 MergeAnimations = args.Any(a => a == "-anim-merge"),
446 NoAnimation = args.Any(a => a == "-noanim")
447 };
448
449 var animBodyFilePath = args.FirstOrDefault(a => a.StartsWith("-anim-body:", StringComparison.Ordinal));
450
451 if (animBodyFilePath != null)
452 {
453 animBodyFilePath = Path.GetFullPath(animBodyFilePath.Substring("-anim-body:".Length));
454 var file = fileManager.OpenFile(animBodyFilePath);
455 exporter.AnimationBody = Totoro.BodyDatReader.Read(file.Descriptors[0]);
456 }
457
458 exporter.ExportFiles(sourceFilePaths);
459
460 return 0;
461 }
462
463 private static int Pack(string[] args)
464 {
465 if (args.Length < 3)
466 {
467 Console.Error.WriteLine("Invalid command line.");
468 return 1;
469 }
470
471 var packer = new DatPacker();
472 var inputPaths = new List<string>();
473
474 if (args[0] == "pack")
475 {
476 for (int i = 1; i < args.Length; i++)
477 {
478 var arg = args[i];
479
480 if (arg == "-out")
481 {
482 i++;
483 packer.TargetFilePath = Path.GetFullPath(args[i]);
484 continue;
485 }
486
487 if (arg.StartsWith("-type:", StringComparison.Ordinal))
488 {
489 switch (arg.Substring(6))
490 {
491 case "nosep":
492 case "pc":
493 packer.TargetTemplateChecksum = InstanceFileHeader.OniPCTemplateChecksum;
494 break;
495
496 case "sep":
497 case "pcdemo":
498 case "macintel":
499 packer.TargetTemplateChecksum = InstanceFileHeader.OniMacTemplateChecksum;
500 break;
501
502 case "ppc":
503 packer.TargetTemplateChecksum = InstanceFileHeader.OniMacTemplateChecksum;
504 packer.TargetBigEndian = true;
505 break;
506
507 default:
508 throw new ArgumentException(string.Format("Unknown output type {0}", arg.Substring(6)));
509 }
510
511 continue;
512 }
513
514 if (Directory.Exists(arg))
515 {
516 arg = Path.GetFullPath(arg);
517 Console.WriteLine("Reading directory {0}", arg);
518 inputPaths.AddRange(Directory.GetFiles(arg, "*.oni", SearchOption.AllDirectories));
519 }
520 else
521 {
522 var dirPath = Path.GetDirectoryName(arg);
523 var fileSpec = Path.GetFileName(arg);
524
525 if (string.IsNullOrEmpty(dirPath))
526 dirPath = Directory.GetCurrentDirectory();
527 else
528 dirPath = Path.GetFullPath(dirPath);
529
530 if (Directory.Exists(dirPath))
531 {
532 foreach (string filePath in Directory.GetFiles(dirPath, fileSpec))
533 {
534 Console.WriteLine("Reading {0}", filePath);
535 inputPaths.Add(filePath);
536 }
537 }
538 }
539 }
540
541 packer.Pack(fileManager, inputPaths);
542 }
543 else
544 {
545 switch (args[0])
546 {
547 case "-import:nosep":
548 case "-import:pc":
549 packer.TargetTemplateChecksum = InstanceFileHeader.OniPCTemplateChecksum;
550 break;
551
552 case "-import:sep":
553 case "-import:pcdemo":
554 case "-import:macintel":
555 packer.TargetTemplateChecksum = InstanceFileHeader.OniMacTemplateChecksum;
556 break;
557
558 case "-import:ppc":
559 packer.TargetTemplateChecksum = InstanceFileHeader.OniMacTemplateChecksum;
560 packer.TargetBigEndian = true;
561 break;
562 }
563
564 for (int i = 1; i < args.Length - 1; i++)
565 inputPaths.Add(Path.GetFullPath(args[i]));
566
567 packer.TargetFilePath = Path.GetFullPath(args[args.Length - 1]);
568 packer.Import(fileManager, inputPaths.ToArray());
569 }
570
571 return 0;
572 }
573
574 private static int Copy(string[] args)
575 {
576 if (args.Length < 3)
577 {
578 Console.Error.WriteLine("Invalid command line.");
579 return 1;
580 }
581
582 var outputDirPath = Path.GetFullPath(args[1]);
583 var inputFilePaths = GetFileList(args, 2);
584 var copy = new InstanceFileOperations();
585
586 copy.Copy(fileManager, inputFilePaths, outputDirPath);
587
588 return 0;
589 }
590
591 private static int Move(string[] args)
592 {
593 if (args.Length < 3)
594 {
595 Console.Error.WriteLine("Invalid command line.");
596 return 1;
597 }
598
599 var outputDirPath = Path.GetFullPath(args[1]);
600 var inputFilePaths = GetFileList(args, 2);
601 var copy = new InstanceFileOperations();
602
603 if (args[0] == "-move:delete")
604 copy.MoveDelete(fileManager, inputFilePaths, outputDirPath);
605 else if (args[0] == "-move:overwrite")
606 copy.MoveOverwrite(fileManager, inputFilePaths, outputDirPath);
607 else
608 copy.Move(fileManager, inputFilePaths, outputDirPath);
609
610 return 0;
611 }
612
613 private static int List(string[] args)
614 {
615 if (args.Length < 2)
616 {
617 Console.Error.WriteLine("Invalid command line.");
618 return 1;
619 }
620
621 string sourceFilePath = Path.GetFullPath(args[1]);
622
623 var file = fileManager.OpenFile(sourceFilePath);
624
625 foreach (var descriptor in file.GetNamedDescriptors())
626 Console.WriteLine(descriptor.FullName);
627
628 return 0;
629 }
630
631 private static int GetDependencies(string[] args)
632 {
633 if (args.Length < 2)
634 {
635 Console.Error.WriteLine("Invalid command line.");
636 return 1;
637 }
638
639 var inputFilePaths = GetFileList(args, 1);
640
641 InstanceFileOperations copy = new InstanceFileOperations();
642 copy.GetDependencies(fileManager, inputFilePaths);
643
644 return 0;
645 }
646
647 private static int PrintVersion()
648 {
649 Console.WriteLine("OniSplit version {0}", Utils.Version);
650 return 0;
651 }
652
653 private static int CreateGrids(string[] args)
654 {
655 if (args.Length < 2)
656 {
657 Console.Error.WriteLine("Invalid command line.");
658 return 1;
659 }
660
661 var filePaths = GetFileList(args, 1);
662
663 var roomsScene = Dae.Reader.ReadFile(filePaths[0]);
664 var geometryMesh = Akira.AkiraDaeReader.Read(filePaths.Skip(1));
665 var gridBuilder = new Akira.RoomGridBuilder(roomsScene, geometryMesh);
666 string outputDirPath = null;
667
668 foreach (string arg in args)
669 {
670 if (arg.StartsWith("-out:", StringComparison.Ordinal))
671 outputDirPath = Path.GetFullPath(arg.Substring(5));
672 }
673
674 if (string.IsNullOrEmpty(outputDirPath))
675 {
676 Console.Error.WriteLine("Output path must be specified");
677 return 1;
678 }
679
680 gridBuilder.Build();
681 AkiraDaeWriter.WriteRooms(gridBuilder.Mesh, Path.GetFileNameWithoutExtension(filePaths[0]), outputDirPath);
682
683 return 0;
684 }
685
686 private static int ExtractRooms(string[] args)
687 {
688 if (args.Length < 2)
689 {
690 Console.Error.WriteLine("Invalid command line.");
691 return 1;
692 }
693
694 string outputFilePath = null;
695
696 foreach (string arg in args)
697 {
698 if (arg.StartsWith("-out:", StringComparison.Ordinal))
699 outputFilePath = Path.GetFullPath(arg.Substring(5));
700 }
701
702 if (string.IsNullOrEmpty(outputFilePath))
703 {
704 Console.Error.WriteLine("Output file path must be specified");
705 return 1;
706 }
707
708 var extractor = new Akira.RoomExtractor(GetFileList(args, 1), outputFilePath);
709 extractor.Extract();
710 return 0;
711 }
712
713 private static int CreateAkira(string[] args)
714 {
715 if (args.Length < 2)
716 {
717 Console.Error.WriteLine("Invalid command line.");
718 return 1;
719 }
720
721 var outputDirPath = Path.GetFullPath(args[1]);
722 var filePaths = GetFileList(args, 2);
723
724 Directory.CreateDirectory(outputDirPath);
725
726 var importedFiles = new Set<string>(StringComparer.OrdinalIgnoreCase);
727 var taskQueue = new Queue<ImporterTask>();
728
729 foreach (string filePath in filePaths)
730 importedFiles.Add(filePath);
731
732 var importer = new AkiraImporter(args);
733
734 Console.WriteLine("Importing {0}", filePaths[0]);
735
736 importer.Import(filePaths, outputDirPath);
737
738 QueueTasks(importedFiles, taskQueue, importer);
739 ExecuteTasks(args, outputDirPath, importedFiles, taskQueue);
740
741 return 0;
742 }
743
744 private static int CreateGeneric(string[] args)
745 {
746 if (args.Length < 2)
747 {
748 Console.Error.WriteLine("Invalid command line.");
749 return 1;
750 }
751
752 var targetType = TemplateTag.NONE;
753 int colonIndex = args[0].IndexOf(':');
754
755 if (colonIndex != -1)
756 {
757 string tagName = args[0].Substring(colonIndex + 1);
758 targetType = (TemplateTag)Enum.Parse(typeof(TemplateTag), tagName, true);
759 }
760
761 string outputDirPath = Path.GetFullPath(args[1]);
762 var filePaths = GetFileList(args, 2);
763
764 Directory.CreateDirectory(outputDirPath);
765
766 var importedFiles = new Set<string>(StringComparer.OrdinalIgnoreCase);
767 var importQueue = new Queue<ImporterTask>();
768
769 foreach (string filePath in filePaths)
770 {
771 if (importedFiles.Add(filePath))
772 importQueue.Enqueue(new ImporterTask(filePath, targetType));
773 }
774
775 ExecuteTasks(args, outputDirPath, importedFiles, importQueue);
776
777 return 0;
778 }
779
780 private static void ExecuteTasks(string[] args, string outputDirPath, Set<string> importedFiles, Queue<ImporterTask> taskQueue)
781 {
782 while (taskQueue.Count > 0)
783 {
784 var task = taskQueue.Dequeue();
785
786 if (!File.Exists(task.FilePath))
787 {
788 Console.Error.WriteLine("File {0} does not exist", task.FilePath);
789 continue;
790 }
791
792 var importer = CreateImporterFromFileName(args, task);
793
794 if (importer == null)
795 {
796 Console.Error.WriteLine("{0} files cannot be imported as {1}", Path.GetExtension(task.FilePath), task.Type);
797 continue;
798 }
799
800 Console.WriteLine("Importing {0}", task.FilePath);
801
802 importer.Import(task.FilePath, outputDirPath);
803
804 QueueTasks(importedFiles, taskQueue, importer);
805 }
806 }
807
808 private static Importer CreateImporterFromFileName(string[] args, ImporterTask task)
809 {
810 Importer importer = null;
811
812 switch (Path.GetExtension(task.FilePath).ToLowerInvariant())
813 {
814 case ".bin":
815 importer = new BinImporter();
816 break;
817
818 case ".xml":
819 importer = new XmlImporter(args);
820 break;
821
822 case ".tga":
823 case ".dds":
824 case ".png":
825 case ".jpg":
826 case ".bmp":
827 case ".tif":
828 if (task.Type == TemplateTag.NONE || task.Type == TemplateTag.TXMP)
829 importer = new Oni.Motoko.TextureImporter(args);
830 break;
831
832 case ".obj":
833 case ".dae":
834 if (task.Type == TemplateTag.NONE || task.Type == TemplateTag.M3GM)
835 importer = new Motoko.GeometryImporter(args);
836 else if (task.Type == TemplateTag.AKEV)
837 importer = new AkiraImporter(args);
838 else if (task.Type == TemplateTag.TRBS)
839 importer = new Totoro.BodySetImporter(args);
840 else if (task.Type == TemplateTag.OBAN)
841 importer = new Physics.ObjectAnimationImporter(args);
842 break;
843
844 case ".wav":
845 if (task.Type == TemplateTag.NONE || task.Type == TemplateTag.SNDD)
846 importer = new WavImporter(args.Any(a => a == "-demo"));
847 break;
848
849 case ".aif":
850 case ".aifc":
851 case ".afc":
852 if (task.Type == TemplateTag.NONE || task.Type == TemplateTag.SNDD)
853 importer = new AifImporter();
854 break;
855
856 case ".txt":
857 if (task.Type == TemplateTag.NONE || task.Type == TemplateTag.SUBT)
858 importer = new SubtitleImporter();
859 break;
860 }
861
862 return importer;
863 }
864
865 private static void QueueTasks(Set<string> imported, Queue<ImporterTask> importQueue, Importer importer)
866 {
867 foreach (ImporterTask child in importer.Dependencies)
868 {
869 if (!imported.Contains(child.FilePath))
870 {
871 imported.Add(child.FilePath);
872 importQueue.Enqueue(child);
873 }
874 }
875 }
876
877 private static int ConvertFilm2Xml(string[] args)
878 {
879 if (args.Length < 3)
880 {
881 Console.Error.WriteLine("Invalid command line.");
882 return 1;
883 }
884
885 var outputDirPath = Path.GetFullPath(args[1]);
886 var inputFilePaths = GetFileList(args, 2);
887
888 Directory.CreateDirectory(outputDirPath);
889
890 foreach (string filePath in inputFilePaths)
891 FilmToXmlConverter.Convert(filePath, outputDirPath);
892
893 return 0;
894 }
895
896 private static int ImportLevel(string[] args)
897 {
898 if (args.Length < 2)
899 {
900 Console.Error.WriteLine("Invalid command line.");
901 return 1;
902 }
903
904 var levelImporter = new Level.LevelImporter
905 {
906 Debug = args.Any(a => a == "-debug")
907 };
908
909 var outputDirPath = Path.GetFullPath(args[1]);
910
911 if (string.IsNullOrEmpty(outputDirPath))
912 {
913 Console.Error.WriteLine("Output path must be specified");
914 return 1;
915 }
916
917 var inputFiles = GetFileList(args, 2);
918
919 if (inputFiles.Count == 0)
920 {
921 Console.Error.WriteLine("No input files specified");
922 return 1;
923 }
924
925 if (inputFiles.Count > 1)
926 {
927 Console.Error.WriteLine("Too many input files specified, only one level can be created at a time");
928 return 1;
929 }
930
931 levelImporter.Import(inputFiles[0], outputDirPath);
932 return 0;
933 }
934
935 private static List<string> GetFileList(string[] args, int startIndex)
936 {
937 var fileSet = new Set<string>(StringComparer.OrdinalIgnoreCase);
938 var fileList = new List<string>();
939
940 foreach (var arg in args.Skip(startIndex))
941 {
942 if (arg[0] == '-')
943 continue;
944
945 string dirPath = Path.GetDirectoryName(arg);
946 string fileSpec = Path.GetFileName(arg);
947
948 if (string.IsNullOrEmpty(dirPath))
949 dirPath = Directory.GetCurrentDirectory();
950 else
951 dirPath = Path.GetFullPath(dirPath);
952
953 if (Directory.Exists(dirPath))
954 {
955 foreach (string filePath in Directory.GetFiles(dirPath, fileSpec))
956 {
957 if (fileSet.Add(filePath))
958 fileList.Add(filePath);
959 }
960 }
961 }
962
963 if (fileList.Count == 0)
964 throw new ArgumentException("No input files found");
965
966 return fileList;
967 }
968 }
969}
Note: See TracBrowser for help on using the repository browser.