source: OniSplit/Program.cs@ 1130

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

Minor fixes and features in SNDD export: "transcoding" forbidden, standard-compliant MSADPCM (with padding and "fact" section), PCM export (with -extract:pcm).

File size: 34.0 KB
RevLine 
[1114]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":
[1130]118 case "-extract:pcm":
[1114]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
370 switch (fileType)
371 {
372 case "aif":
373 exporter = new AifExporter(fileManager, outputDirPath);
374 break;
375 case "wav":
376 exporter = new WavExporter(fileManager, outputDirPath);
377 break;
[1130]378 case "pcm":
379 exporter = new WavExporter(fileManager, outputDirPath, true);
380 break;
[1114]381 default:
382 throw new NotSupportedException(string.Format("Unsupported file type {0}", fileType));
383 }
384
385 exporter.ExportFiles(sourceFilePaths);
386
387 return 0;
388 }
389
390 private static int ExportGeometry(string[] args)
391 {
392 if (args.Length < 3)
393 {
394 Console.Error.WriteLine("Invalid command line.");
395 return 1;
396 }
397
398 int i = args[0].IndexOf(':');
399 string fileType = null;
400
401 if (i != -1)
402 fileType = args[0].Substring(i + 1);
403
404 var outputDirPath = Path.GetFullPath(args[1]);
405 var sourceFilePaths = GetFileList(args, 2);
406
407 var exporter = new DaeExporter(args, fileManager, outputDirPath, fileType);
408 exporter.ExportFiles(sourceFilePaths);
409
410 return 0;
411 }
412
413 private static int ExportSubtitles(string[] args)
414 {
415 if (args.Length < 3)
416 {
417 Console.Error.WriteLine("Invalid command line.");
418 return 1;
419 }
420
421 var outputDirPath = Path.GetFullPath(args[1]);
422 var sourceFilePaths = GetFileList(args, 2);
423
424 var exporter = new SubtitleExporter(fileManager, outputDirPath);
425 exporter.ExportFiles(sourceFilePaths);
426
427 return 0;
428 }
429
430 private static int ExportXml(string[] args)
431 {
432 if (args.Length < 3)
433 {
434 Console.Error.WriteLine("Invalid command line.");
435 return 1;
436 }
437
438 var outputDirPath = Path.GetFullPath(args[1]);
439 var sourceFilePaths = GetFileList(args, 2);
440
441 var exporter = new XmlExporter(fileManager, outputDirPath)
442 {
443 Recursive = args.Any(a => a == "-recurse"),
444 MergeAnimations = args.Any(a => a == "-anim-merge"),
445 NoAnimation = args.Any(a => a == "-noanim")
446 };
447
448 var animBodyFilePath = args.FirstOrDefault(a => a.StartsWith("-anim-body:", StringComparison.Ordinal));
449
450 if (animBodyFilePath != null)
451 {
452 animBodyFilePath = Path.GetFullPath(animBodyFilePath.Substring("-anim-body:".Length));
453 var file = fileManager.OpenFile(animBodyFilePath);
454 exporter.AnimationBody = Totoro.BodyDatReader.Read(file.Descriptors[0]);
455 }
456
457 exporter.ExportFiles(sourceFilePaths);
458
459 return 0;
460 }
461
462 private static int Pack(string[] args)
463 {
464 if (args.Length < 3)
465 {
466 Console.Error.WriteLine("Invalid command line.");
467 return 1;
468 }
469
470 var packer = new DatPacker();
471 var inputPaths = new List<string>();
472
473 if (args[0] == "pack")
474 {
475 for (int i = 1; i < args.Length; i++)
476 {
477 var arg = args[i];
478
479 if (arg == "-out")
480 {
481 i++;
482 packer.TargetFilePath = Path.GetFullPath(args[i]);
483 continue;
484 }
485
486 if (arg.StartsWith("-type:", StringComparison.Ordinal))
487 {
488 switch (arg.Substring(6))
489 {
490 case "nosep":
491 case "pc":
492 packer.TargetTemplateChecksum = InstanceFileHeader.OniPCTemplateChecksum;
493 break;
494
495 case "sep":
496 case "pcdemo":
497 case "macintel":
498 packer.TargetTemplateChecksum = InstanceFileHeader.OniMacTemplateChecksum;
499 break;
500
501 case "ppc":
502 packer.TargetTemplateChecksum = InstanceFileHeader.OniMacTemplateChecksum;
503 packer.TargetBigEndian = true;
504 break;
505
506 default:
507 throw new ArgumentException(string.Format("Unknown output type {0}", arg.Substring(6)));
508 }
509
510 continue;
511 }
512
513 if (Directory.Exists(arg))
514 {
515 arg = Path.GetFullPath(arg);
516 Console.WriteLine("Reading directory {0}", arg);
517 inputPaths.AddRange(Directory.GetFiles(arg, "*.oni", SearchOption.AllDirectories));
518 }
519 else
520 {
521 var dirPath = Path.GetDirectoryName(arg);
522 var fileSpec = Path.GetFileName(arg);
523
524 if (string.IsNullOrEmpty(dirPath))
525 dirPath = Directory.GetCurrentDirectory();
526 else
527 dirPath = Path.GetFullPath(dirPath);
528
529 if (Directory.Exists(dirPath))
530 {
531 foreach (string filePath in Directory.GetFiles(dirPath, fileSpec))
532 {
533 Console.WriteLine("Reading {0}", filePath);
534 inputPaths.Add(filePath);
535 }
536 }
537 }
538 }
539
540 packer.Pack(fileManager, inputPaths);
541 }
542 else
543 {
544 switch (args[0])
545 {
546 case "-import:nosep":
547 case "-import:pc":
548 packer.TargetTemplateChecksum = InstanceFileHeader.OniPCTemplateChecksum;
549 break;
550
551 case "-import:sep":
552 case "-import:pcdemo":
553 case "-import:macintel":
554 packer.TargetTemplateChecksum = InstanceFileHeader.OniMacTemplateChecksum;
555 break;
556
557 case "-import:ppc":
558 packer.TargetTemplateChecksum = InstanceFileHeader.OniMacTemplateChecksum;
559 packer.TargetBigEndian = true;
560 break;
561 }
562
563 for (int i = 1; i < args.Length - 1; i++)
564 inputPaths.Add(Path.GetFullPath(args[i]));
565
566 packer.TargetFilePath = Path.GetFullPath(args[args.Length - 1]);
567 packer.Import(fileManager, inputPaths.ToArray());
568 }
569
570 return 0;
571 }
572
573 private static int Copy(string[] args)
574 {
575 if (args.Length < 3)
576 {
577 Console.Error.WriteLine("Invalid command line.");
578 return 1;
579 }
580
581 var outputDirPath = Path.GetFullPath(args[1]);
582 var inputFilePaths = GetFileList(args, 2);
583 var copy = new InstanceFileOperations();
584
585 copy.Copy(fileManager, inputFilePaths, outputDirPath);
586
587 return 0;
588 }
589
590 private static int Move(string[] args)
591 {
592 if (args.Length < 3)
593 {
594 Console.Error.WriteLine("Invalid command line.");
595 return 1;
596 }
597
598 var outputDirPath = Path.GetFullPath(args[1]);
599 var inputFilePaths = GetFileList(args, 2);
600 var copy = new InstanceFileOperations();
601
602 if (args[0] == "-move:delete")
603 copy.MoveDelete(fileManager, inputFilePaths, outputDirPath);
604 else if (args[0] == "-move:overwrite")
605 copy.MoveOverwrite(fileManager, inputFilePaths, outputDirPath);
606 else
607 copy.Move(fileManager, inputFilePaths, outputDirPath);
608
609 return 0;
610 }
611
612 private static int List(string[] args)
613 {
614 if (args.Length < 2)
615 {
616 Console.Error.WriteLine("Invalid command line.");
617 return 1;
618 }
619
620 string sourceFilePath = Path.GetFullPath(args[1]);
621
622 var file = fileManager.OpenFile(sourceFilePath);
623
624 foreach (var descriptor in file.GetNamedDescriptors())
625 Console.WriteLine(descriptor.FullName);
626
627 return 0;
628 }
629
630 private static int GetDependencies(string[] args)
631 {
632 if (args.Length < 2)
633 {
634 Console.Error.WriteLine("Invalid command line.");
635 return 1;
636 }
637
638 var inputFilePaths = GetFileList(args, 1);
639
640 InstanceFileOperations copy = new InstanceFileOperations();
641 copy.GetDependencies(fileManager, inputFilePaths);
642
643 return 0;
644 }
645
646 private static int PrintVersion()
647 {
648 Console.WriteLine("OniSplit version {0}", Utils.Version);
649 return 0;
650 }
651
652 private static int CreateGrids(string[] args)
653 {
654 if (args.Length < 2)
655 {
656 Console.Error.WriteLine("Invalid command line.");
657 return 1;
658 }
659
660 var filePaths = GetFileList(args, 1);
661
662 var roomsScene = Dae.Reader.ReadFile(filePaths[0]);
663 var geometryMesh = Akira.AkiraDaeReader.Read(filePaths.Skip(1));
664 var gridBuilder = new Akira.RoomGridBuilder(roomsScene, geometryMesh);
665 string outputDirPath = null;
666
667 foreach (string arg in args)
668 {
669 if (arg.StartsWith("-out:", StringComparison.Ordinal))
670 outputDirPath = Path.GetFullPath(arg.Substring(5));
671 }
672
673 if (string.IsNullOrEmpty(outputDirPath))
674 {
675 Console.Error.WriteLine("Output path must be specified");
676 return 1;
677 }
678
679 gridBuilder.Build();
680 AkiraDaeWriter.WriteRooms(gridBuilder.Mesh, Path.GetFileNameWithoutExtension(filePaths[0]), outputDirPath);
681
682 return 0;
683 }
684
685 private static int ExtractRooms(string[] args)
686 {
687 if (args.Length < 2)
688 {
689 Console.Error.WriteLine("Invalid command line.");
690 return 1;
691 }
692
693 string outputFilePath = null;
694
695 foreach (string arg in args)
696 {
697 if (arg.StartsWith("-out:", StringComparison.Ordinal))
698 outputFilePath = Path.GetFullPath(arg.Substring(5));
699 }
700
701 if (string.IsNullOrEmpty(outputFilePath))
702 {
703 Console.Error.WriteLine("Output file path must be specified");
704 return 1;
705 }
706
707 var extractor = new Akira.RoomExtractor(GetFileList(args, 1), outputFilePath);
708 extractor.Extract();
709 return 0;
710 }
711
712 private static int CreateAkira(string[] args)
713 {
714 if (args.Length < 2)
715 {
716 Console.Error.WriteLine("Invalid command line.");
717 return 1;
718 }
719
720 var outputDirPath = Path.GetFullPath(args[1]);
721 var filePaths = GetFileList(args, 2);
722
723 Directory.CreateDirectory(outputDirPath);
724
725 var importedFiles = new Set<string>(StringComparer.OrdinalIgnoreCase);
726 var taskQueue = new Queue<ImporterTask>();
727
728 foreach (string filePath in filePaths)
729 importedFiles.Add(filePath);
730
731 var importer = new AkiraImporter(args);
732
733 Console.WriteLine("Importing {0}", filePaths[0]);
734
735 importer.Import(filePaths, outputDirPath);
736
737 QueueTasks(importedFiles, taskQueue, importer);
738 ExecuteTasks(args, outputDirPath, importedFiles, taskQueue);
739
740 return 0;
741 }
742
743 private static int CreateGeneric(string[] args)
744 {
745 if (args.Length < 2)
746 {
747 Console.Error.WriteLine("Invalid command line.");
748 return 1;
749 }
750
751 var targetType = TemplateTag.NONE;
752 int colonIndex = args[0].IndexOf(':');
753
754 if (colonIndex != -1)
755 {
756 string tagName = args[0].Substring(colonIndex + 1);
757 targetType = (TemplateTag)Enum.Parse(typeof(TemplateTag), tagName, true);
758 }
759
760 string outputDirPath = Path.GetFullPath(args[1]);
761 var filePaths = GetFileList(args, 2);
762
763 Directory.CreateDirectory(outputDirPath);
764
765 var importedFiles = new Set<string>(StringComparer.OrdinalIgnoreCase);
766 var importQueue = new Queue<ImporterTask>();
767
768 foreach (string filePath in filePaths)
769 {
770 if (importedFiles.Add(filePath))
771 importQueue.Enqueue(new ImporterTask(filePath, targetType));
772 }
773
774 ExecuteTasks(args, outputDirPath, importedFiles, importQueue);
775
776 return 0;
777 }
778
779 private static void ExecuteTasks(string[] args, string outputDirPath, Set<string> importedFiles, Queue<ImporterTask> taskQueue)
780 {
781 while (taskQueue.Count > 0)
782 {
783 var task = taskQueue.Dequeue();
784
785 if (!File.Exists(task.FilePath))
786 {
787 Console.Error.WriteLine("File {0} does not exist", task.FilePath);
788 continue;
789 }
790
791 var importer = CreateImporterFromFileName(args, task);
792
793 if (importer == null)
794 {
795 Console.Error.WriteLine("{0} files cannot be imported as {1}", Path.GetExtension(task.FilePath), task.Type);
796 continue;
797 }
798
799 Console.WriteLine("Importing {0}", task.FilePath);
800
801 importer.Import(task.FilePath, outputDirPath);
802
803 QueueTasks(importedFiles, taskQueue, importer);
804 }
805 }
806
807 private static Importer CreateImporterFromFileName(string[] args, ImporterTask task)
808 {
809 Importer importer = null;
810
811 switch (Path.GetExtension(task.FilePath).ToLowerInvariant())
812 {
813 case ".bin":
814 importer = new BinImporter();
815 break;
816
817 case ".xml":
818 importer = new XmlImporter(args);
819 break;
820
821 case ".tga":
822 case ".dds":
823 case ".png":
824 case ".jpg":
825 case ".bmp":
826 case ".tif":
827 if (task.Type == TemplateTag.NONE || task.Type == TemplateTag.TXMP)
828 importer = new Oni.Motoko.TextureImporter(args);
829 break;
830
831 case ".obj":
832 case ".dae":
833 if (task.Type == TemplateTag.NONE || task.Type == TemplateTag.M3GM)
834 importer = new Motoko.GeometryImporter(args);
835 else if (task.Type == TemplateTag.AKEV)
836 importer = new AkiraImporter(args);
837 else if (task.Type == TemplateTag.TRBS)
838 importer = new Totoro.BodySetImporter(args);
839 else if (task.Type == TemplateTag.OBAN)
840 importer = new Physics.ObjectAnimationImporter(args);
841 break;
842
843 case ".wav":
844 if (task.Type == TemplateTag.NONE || task.Type == TemplateTag.SNDD)
845 importer = new WavImporter();
846 break;
847
848 case ".aif":
849 case ".aifc":
850 case ".afc":
851 if (task.Type == TemplateTag.NONE || task.Type == TemplateTag.SNDD)
852 importer = new AifImporter();
853 break;
854
855 case ".txt":
856 if (task.Type == TemplateTag.NONE || task.Type == TemplateTag.SUBT)
857 importer = new SubtitleImporter();
858 break;
859 }
860
861 return importer;
862 }
863
864 private static void QueueTasks(Set<string> imported, Queue<ImporterTask> importQueue, Importer importer)
865 {
866 foreach (ImporterTask child in importer.Dependencies)
867 {
868 if (!imported.Contains(child.FilePath))
869 {
870 imported.Add(child.FilePath);
871 importQueue.Enqueue(child);
872 }
873 }
874 }
875
876 private static int ConvertFilm2Xml(string[] args)
877 {
878 if (args.Length < 3)
879 {
880 Console.Error.WriteLine("Invalid command line.");
881 return 1;
882 }
883
884 var outputDirPath = Path.GetFullPath(args[1]);
885 var inputFilePaths = GetFileList(args, 2);
886
887 Directory.CreateDirectory(outputDirPath);
888
889 foreach (string filePath in inputFilePaths)
890 FilmToXmlConverter.Convert(filePath, outputDirPath);
891
892 return 0;
893 }
894
895 private static int ImportLevel(string[] args)
896 {
897 if (args.Length < 2)
898 {
899 Console.Error.WriteLine("Invalid command line.");
900 return 1;
901 }
902
903 var levelImporter = new Level.LevelImporter
904 {
905 Debug = args.Any(a => a == "-debug")
906 };
907
908 var outputDirPath = Path.GetFullPath(args[1]);
909
910 if (string.IsNullOrEmpty(outputDirPath))
911 {
912 Console.Error.WriteLine("Output path must be specified");
913 return 1;
914 }
915
916 var inputFiles = GetFileList(args, 2);
917
918 if (inputFiles.Count == 0)
919 {
920 Console.Error.WriteLine("No input files specified");
921 return 1;
922 }
923
924 if (inputFiles.Count > 1)
925 {
926 Console.Error.WriteLine("Too many input files specified, only one level can be created at a time");
927 return 1;
928 }
929
930 levelImporter.Import(inputFiles[0], outputDirPath);
931 return 0;
932 }
933
934 private static List<string> GetFileList(string[] args, int startIndex)
935 {
936 var fileSet = new Set<string>(StringComparer.OrdinalIgnoreCase);
937 var fileList = new List<string>();
938
939 foreach (var arg in args.Skip(startIndex))
940 {
941 if (arg[0] == '-')
942 continue;
943
944 string dirPath = Path.GetDirectoryName(arg);
945 string fileSpec = Path.GetFileName(arg);
946
947 if (string.IsNullOrEmpty(dirPath))
948 dirPath = Directory.GetCurrentDirectory();
949 else
950 dirPath = Path.GetFullPath(dirPath);
951
952 if (Directory.Exists(dirPath))
953 {
954 foreach (string filePath in Directory.GetFiles(dirPath, fileSpec))
955 {
956 if (fileSet.Add(filePath))
957 fileList.Add(filePath);
958 }
959 }
960 }
961
962 if (fileList.Count == 0)
963 throw new ArgumentException("No input files found");
964
965 return fileList;
966 }
967 }
968}
Note: See TracBrowser for help on using the repository browser.