예제 #1
0
        private static void ConvertMB()
        {
            var model = Resource.Load <Model>(Options.Input);

            switch (Options.OutputFormat)
            {
            case OutputFormat.PB:
                var modelPack = new ModelPack();
                modelPack.Models.Add(model);
                modelPack.Save(Options.Output);
                break;

            case OutputFormat.MB:
                model.Save(Options.Output);
                break;

            case OutputFormat.OBJ:
            case OutputFormat.DAE:
            case OutputFormat.FBX:
                if (Options.OutputFormat == OutputFormat.DAE || Options.OutputFormat == OutputFormat.FBX)
                {
                    FbxModelExporter.Instance.Export(model, Options.Output, FbxConfig, null);
                }
                else
                {
                    AssimpModelExporter.Instance.Export(model, Options.Output);
                }
                break;

            default:
                throw new Exception("Unsupported output format");
            }
        }
예제 #2
0
        private static void ConvertPB()
        {
            var modelPack = new ModelPack(Options.Input);

            switch (Options.OutputFormat)
            {
            case OutputFormat.PB:
                modelPack.Save(Options.Output);
                break;

            case OutputFormat.MB:
                for (int i = 0; i < modelPack.Models.Count; i++)
                {
                    modelPack.Models[i].Save(modelPack.Models.Count == 1 ? Options.Output : $"{Path.GetFileNameWithoutExtension( Options.Output )}_{i}.MB");
                }
                break;

            case OutputFormat.OBJ:
            case OutputFormat.DAE:
            case OutputFormat.FBX:
                for (int i = 0; i < modelPack.Models.Count; i++)
                {
                    var modelOutfilePath = modelPack.Models.Count == 1 ?
                                           Options.Output :
                                           $"{Path.GetFileNameWithoutExtension( Options.Output )}_{i}.{Options.OutputFormat}";

                    if (Options.OutputFormat == OutputFormat.DAE || Options.OutputFormat == OutputFormat.FBX)
                    {
                        FbxModelExporter.Instance.Export(modelPack.Models[i], modelOutfilePath, FbxConfig, modelPack.TexturePack);
                    }
                    else
                    {
                        AssimpModelExporter.Instance.Export(modelPack.Models[i], modelOutfilePath, modelPack.TexturePack);
                    }

                    if (Options.Assimp.OutputPbMotion)
                    {
                        for (int j = 0; j < modelPack.MotionPacks.Count; j++)
                        {
                            for (int k = 0; k < modelPack.MotionPacks[j].Motions.Count; k++)
                            {
                                var outfilePath = modelPack.MotionPacks.Count == 1 ?
                                                  $"{Path.GetFileNameWithoutExtension( Options.Output )}_m_{j}.{Options.OutputFormat}" :
                                                  $"{Path.GetFileNameWithoutExtension( Options.Output )}_mp_{j}_m_{k}.{Options.OutputFormat}";

                                AssimpMotionExporter.Instance.Export(modelPack.Models[i], modelPack.MotionPacks[j].Motions[k], outfilePath);
                            }
                        }
                    }
                }
                break;

            default:
                throw new Exception("Unsupported output format");
            }
        }
예제 #3
0
 private static void RemoveChunks()
 {
     foreach (var gmd in Directory.GetFiles(Input.retargetFolder, "*.GMD", SearchOption.TopDirectoryOnly))
     {
         var modelPack    = ModuleImportUtilities.ImportFile <ModelPack>(gmd);
         var newModelPack = new ModelPack();
         newModelPack.Version       = modelPack.Version;
         newModelPack.Textures      = modelPack.Textures;
         newModelPack.Materials     = modelPack.Materials;
         newModelPack.Model         = modelPack.Model;
         newModelPack.AnimationPack = modelPack.AnimationPack;
         newModelPack.Save(gmd);
     }
 }
예제 #4
0
        private static void OpenAndSaveModelPackBatchTest()
        {
            if (!Directory.Exists("unique_models"))
            {
                FindUniqueFiles("unique_models", @"D:\Modding\DDS3", ".PB");
            }

            if (!Directory.Exists("unique_lb"))
            {
                FindUniqueFiles("unique_lb", @"D:\Modding\DDS3", ".LB");
            }

            if (!Directory.Exists("unique_lb_extracted"))
            {
                Directory.CreateDirectory("unique_lb_extracted");
                var checksums = new HashSet <string>();
                Parallel.ForEach(Directory.EnumerateFiles("unique_lb"), (path) =>
                {
                    var fileName = Path.GetFileNameWithoutExtension(path);
                    var outPath  = $"unique_lb_extracted\\";
                    Directory.CreateDirectory(outPath);

                    using (var lb = new AtlusFileSystemLibrary.FileSystems.LB.LBFileSystem())
                    {
                        lb.Load(path);

                        foreach (var file in lb.EnumerateFiles())
                        {
                            var info = lb.GetInfo(file);
                            using (var stream = lb.OpenFile(file))
                            {
                                var checksum    = GetChecksum(stream);
                                stream.Position = 0;
                                var extract     = false;

                                lock ( checksums )
                                {
                                    if (!checksums.Contains(checksum))
                                    {
                                        checksums.Add(checksum);
                                        extract = true;
                                    }
                                }

                                if (extract)
                                {
                                    var nameParts = Path.GetFileNameWithoutExtension(path).Split(new[] { '_' });
                                    Array.Resize(ref nameParts, nameParts.Length - 1);

                                    using (var fileStream =
                                               File.Create(Path.Combine(outPath, string.Concat(nameParts) + "_" + file + "_" + checksum + "." + info.Extension)
                                                           ))
                                    {
                                        Console.WriteLine($"Extracting: {fileName} #{file} ({info.UserId:D2}, {info.Extension})");
                                        stream.CopyTo(fileStream);
                                    }
                                }
                            }
                        }
                    }
                });
            }

            var uniqueValues = new HashSet <MeshFlags>();
            var frequencyMap = new ConcurrentDictionary <MeshFlags, int>();

            var paths = Directory.EnumerateFiles("unique_models", "*.PB", SearchOption.AllDirectories).ToList();
            var done  = 0;

            //foreach ( var path in paths )
            Parallel.ForEach(paths, new ParallelOptions()
            {
                MaxDegreeOfParallelism = 16
            }, (path) =>
            {
                Console.WriteLine(Path.GetFileName(path));
                var modelPack = new ModelPack(path);
                new ModelPack(modelPack.Save());
                //modelPack.Save( path + ".out" );
                //new ModelPack( path + ".out" );
                //ExportObj( modelPack, Path.GetFileNameWithoutExtension( path ) + ".obj" );
            }
                             );

            //var modelPack = new ModelPack( @"D:\Programming\Repos\DDS3-Model-Studio\Source\DDS3ModelLibraryCLI\bin\Debug\unique_models\tiaki_DF1D93D2EC3ED36D63239A1A2B27ED1745DA9991F231884EA7BC5FAF291F74AA.PB" );
            //modelPack.Save( @"D:\Programming\Repos\DDS3-Model-Studio\Source\DDS3ModelLibraryCLI\bin\Debug\unique_models\tiaki_DF1D93D2EC3ED36D63239A1A2B27ED1745DA9991F231884EA7BC5FAF291F74AA.PB" + ".out" );


            //foreach ( var kvp in frequencyMap.OrderBy( x => x.Value ) )
            //{
            //    Console.WriteLine( kvp.Value + " " + kvp.Key );
            //}

            //var paths = Directory.EnumerateFiles( "unique_models", "*.PB", SearchOption.AllDirectories ).ToList();
            //var done = 0;
            //Parallel.ForEach( paths, new ParallelOptions() { MaxDegreeOfParallelism = 8 }, ( path ) =>
            //{
            //    //Console.WriteLine( Path.GetFileName( path ) );
            //    var modelPack = new ModelPack( path );
            //    //modelPack.Save( path + ".out" );
            //    //File.Delete( path + ".out" );
            //    //modelPack.Save();
            //} );

            //var done = 0;
            //Parallel.ForEach( paths, new ParallelOptions() { MaxDegreeOfParallelism = 8 }, ( path ) =>
            //{
            //    Console.WriteLine( Path.GetFileName( path ) );

            //    var outPath = "unique_models\\" + Path.GetFileName( path ) + ".PB";

            //    if ( Path.GetExtension( path ) == ".PAC" )
            //    {
            //        using ( var reader = new EndianBinaryReader( path, Endianness.Little ) )
            //        {
            //            reader.Position = 0x24;
            //            var size = reader.ReadInt32();
            //            reader.Position += 4;
            //            var offset = reader.ReadInt32();
            //            using ( var fileStream = File.Create( outPath ) )
            //                new StreamView( reader.BaseStream, offset, size ).CopyTo( fileStream );
            //        }
            //    }
            //    else
            //    {
            //        File.Copy( path, outPath, true );
            //    }
            //} );
        }
예제 #5
0
        private static void OpenAndSaveModelPackTest()
        {
            var modelPack = new ModelPack(@"..\..\..\..\Resources\player_a.PB");

            modelPack.Save(@"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\model\field\player_a.PB");
        }
예제 #6
0
        private static void Main(string[] args)
        {
            {
                File.Delete("test.fbx");
                var modelPack = new ModelPack(@"D:\dumps\smt3_ntsc\DDS3\model\field\player_a.PB");
                //var modelPack = new ModelPack( @"D:\dumps\smt3_ntsc\DDS3\model\devil\on\0x126_on.PB");
                FbxModelExporter.Instance.Export(modelPack.Models[0], "test.fbx", modelPack.TexturePack);
                return;

                //AssimpModelExporter.Instance.Export( modelPack.Models[ 0 ], "player_a.dae", modelPack.TexturePack );
                //for ( var i = 0; i < modelPack.MotionPacks[ 0 ].Motions.Count; i++ )
                //{
                //    var motion = modelPack.MotionPacks[ 0 ].Motions[ i ];
                //    if ( motion == null )
                //        continue;

                //    AssimpMotionExporter.Instance.Export( modelPack.Models[ 0 ], motion, $"player_a_motion_{i:D2}.dae" );
                //}

                var newMotion =
                    AssimpMotionImporter.Instance.Import(@"D:\Users\smart\Desktop\nocturne_player_a_fortnite.fbx",
                                                         new AssimpMotionImporter.Config
                {
                    NodeIndexResolver = n => modelPack.Models[0].Nodes.FindIndex(x => x.Name == n)
                });
                for (int i = 0; i < modelPack.MotionPacks[0].Motions.Count; i++)
                {
                    modelPack.MotionPacks[0].Motions[i] = newMotion;
                }

                modelPack.Save(@"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\model\field\player_a.PB");
            }

            {
                var lb = new LBFileSystem();
                lb.Load(@"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\fld\f\f037\_f037_027.LB");

                var f1Handle = lb.GetHandle("F1");

                FieldScene f1;
                using (var stream = lb.OpenFile(f1Handle))
                    f1 = new FieldScene(stream, true);

                foreach (var obj in f1.Objects)
                {
                    switch (obj.ResourceType)
                    {
                    case FieldObjectResourceType.Model:
                    {
                        var model = ( Model )obj.Resource;
                        foreach (var material in model.Materials)
                        {
                            if (material.TextureId.HasValue)
                            {
                                material.TextureId = 0;
                            }

                            material.Color1      = material.Color2 = material.Color3 = material.Color4 = material.Color5 = null;
                            material.Float1      = null;
                            material.FloatArray1 = material.FloatArray2 = material.FloatArray3 = null;
                        }

                        foreach (var node in model.Nodes)
                        {
                            if (node.Geometry == null)
                            {
                                continue;
                            }

                            foreach (var _mesh in node.Geometry.Meshes)
                            {
                                if (_mesh is MeshType1 mesh)
                                {
                                    foreach (var batch in mesh.Batches)
                                    {
                                        batch.Flags &= ~MeshFlags.Normal;
                                        batch.Flags &= ~MeshFlags.Color;
                                    }
                                }
                            }
                        }
                    }
                    break;

                    case FieldObjectResourceType.Type3:
                        break;

                    case FieldObjectResourceType.TextureListFileName:
                        break;

                    case FieldObjectResourceType.Effect:
                        break;

                    case FieldObjectResourceType.Light:
                        break;
                    }
                }
                ExportObj(f1);

                lb.AddFile(f1Handle, f1.Save(), true, ConflictPolicy.Replace);

                var tbHandle    = lb.GetHandle("TBN");
                var texturePack = new TexturePack();
                texturePack.Textures.Add(new Texture(new Bitmap(@"D:\Modding\Tools\magenta.png")));
                lb.AddFile(tbHandle, texturePack.Save(), true, ConflictPolicy.Replace);

                lb.Save(@"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\fld\f\f037\f037_027.LB");
            }

            //OpenAndSaveModelPackTest();
            //ReplaceF1Test();
            //ReplaceModelTest();
            //OpenAndSaveModelPackBatchTest();
            //return;
            //ExportObj( new ModelPack( @"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\model\field\player_b.PB" ) );
            //return;
            //OpenAndSaveModelPackBatchTest();return;
            //OpenAndSaveFieldSceneBatchTest();return;
            //ReplaceModelTest();return;

            //var modelPack = new ModelPack( @"..\..\..\..\Resources\player_a.PB" );
            //var modelPack = new ModelPack( @"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\model\field\player_a.PB" );

            //using ( var writer = File.CreateText( "test.obj" ) )
            //{
            //    var vertexBaseIndex = 0;

            //    foreach ( var model in modelPack.Models )
            //    {
            //        foreach ( var node in model.Nodes )
            //        {
            //            if ( node.Geometry == null )
            //                continue;

            //            for ( var meshIndex = 0; meshIndex < node.Geometry.Meshes.Count; meshIndex++ )
            //            {
            //                var _mesh = node.Geometry.Meshes[ meshIndex ];
            //                if ( _mesh.Type != MeshType.Type7 )
            //                    continue;

            //                var mesh = ( MeshType7 ) _mesh;
            //                var positions = new Vector3[mesh.VertexCount];
            //                var normals   = new Vector3[positions.Length];
            //                var weights   = new List<(short NodeIndex, float Weight)>[positions.Length];
            //                var texCoords = new Vector2[positions.Length];
            //                var batchVertexBaseIndex = 0;

            //                foreach ( var batch in mesh.Batches )
            //                {
            //                    for ( var nodeBatchIndex = 0; nodeBatchIndex < batch.NodeBatches.Count; nodeBatchIndex++ )
            //                    {
            //                        var nodeBatch          = batch.NodeBatches[ nodeBatchIndex ];
            //                        var nodeWorldTransform = model.Nodes[ nodeBatch.NodeIndex ].WorldTransform;

            //                        for ( int i = 0; i < nodeBatch.Positions.Length; i++ )
            //                        {
            //                            var position = new Vector3( nodeBatch.Positions[i].X, nodeBatch.Positions[i].Y,
            //                                                        nodeBatch.Positions[i].Z );
            //                            var weight                     = nodeBatch.Positions[i].W;
            //                            var weightedNodeWorldTransform = nodeWorldTransform * weight;
            //                            var weightedWorldPosition      = Vector3.Transform( position, weightedNodeWorldTransform );
            //                            positions[batchVertexBaseIndex + i] += weightedWorldPosition;
            //                            if ( weights[batchVertexBaseIndex + i] == null )
            //                                weights[batchVertexBaseIndex + i] = new List<(short NodeIndex, float Weight)>();
            //                            weights[batchVertexBaseIndex + i].Add( (nodeBatch.NodeIndex, weight) );
            //                            normals[batchVertexBaseIndex + i] += Vector3.TransformNormal( nodeBatch.Normals[i], weightedNodeWorldTransform );
            //                        }
            //                    }

            //                    Array.Copy( batch.TexCoords, 0, texCoords, batchVertexBaseIndex, batch.TexCoords.Length );

            //                    //foreach ( var position in positions )
            //                    //{
            //                    //    writer.WriteLine( $"v {position.X} {position.Y} {position.Z}" );
            //                    //}

            //                    //foreach ( var normal in normals )
            //                    //{
            //                    //    writer.WriteLine( $"vn {normal.X} {normal.Y} {normal.Z}" );
            //                    //}

            //                    //foreach ( var texCoord in batch.TexCoords )
            //                    //{
            //                    //    writer.WriteLine( $"vt {texCoord.X} {texCoord.Y}" );
            //                    //}

            //                    batchVertexBaseIndex += batch.VertexCount;
            //                }

            //                foreach ( var position in positions )
            //                {
            //                    writer.WriteLine( $"v {position.X} {position.Y} {position.Z}" );
            //                }

            //                foreach ( var normal in normals )
            //                {
            //                    writer.WriteLine( $"vn {normal.X} {normal.Y} {normal.Z}" );
            //                }

            //                foreach ( var texCoord in texCoords )
            //                {
            //                    writer.WriteLine( $"vt {texCoord.X} {texCoord.Y}" );
            //                }

            //                //// Find unique node indices used by the mesh (max 4 per mesh!)
            //                //var usedNodeIndices = weights.SelectMany( x => x.Select( y => y.NodeIndex ) ).Distinct().ToList();

            //                //// Calculate node index usage frequency
            //                //var usedNodeIndicesFrequency = new Dictionary<int, int>();
            //                //for ( int i = 0; i < usedNodeIndices.Count; i++ )
            //                //    usedNodeIndicesFrequency[usedNodeIndices[i]] = 0;

            //                //for ( int j = 0; j < positions.Length; j++ )
            //                //{
            //                //    foreach ( var (nodeIndex, _) in weights[j] )
            //                //        ++usedNodeIndicesFrequency[nodeIndex];
            //                //}

            //                //// Sort used node indices by frequency
            //                //usedNodeIndices = usedNodeIndices.OrderBy( x => usedNodeIndicesFrequency[ x ] ).ToList();

            //                //// Start building batches
            //                //var vertexIndexRemap     = new Dictionary<int, int>();
            //                //var batches = new List<MeshType7Batch>();
            //                //batchVertexBaseIndex = 0;

            //                //while ( vertexIndexRemap.Count < positions.Length )
            //                //{
            //                //    var batchVertexCount = Math.Min( 24, positions.Length - vertexIndexRemap.Count );
            //                //    var batch = new MeshType7Batch();
            //                //    var batchVertexIndexRemap = new Dictionary<int, int>();
            //                //    var batchTexCoords = new List<Vector2>();

            //                //    // req. all vertices to use the same set of node indices
            //                //    for ( var i = 0; i < usedNodeIndices.Count; i++ )
            //                //    {
            //                //        var nodeIndex = usedNodeIndices[i];
            //                //        var nodeWorldTransform = model.Nodes[nodeIndex].WorldTransform;
            //                //        var nodeWorldTransformInv = nodeWorldTransform.Inverted();

            //                //        // get all verts with this index
            //                //        var nodePositions = new List<Vector4>();
            //                //        var nodeNormals = new List<Vector3>();

            //                //        for ( int j = 0; j < positions.Length; j++ )
            //                //        {
            //                //            // Skip this vertex if it has already been processed before
            //                //            if ( vertexIndexRemap.ContainsKey( j ) )
            //                //                continue;

            //                //            foreach ( (short NodeIndex, float Weight) in weights[j] )
            //                //            {
            //                //                if ( NodeIndex != nodeIndex )
            //                //                    continue;

            //                //                // Transform position and normal to model space
            //                //                var position = Vector3.Transform( positions[j], nodeWorldTransformInv );
            //                //                var normal = Vector3.TransformNormal( normals[j], nodeWorldTransformInv );

            //                //                // Add entry to vertex remap, and add the model space positions and normals to our lists
            //                //                batchVertexIndexRemap[j] = batchVertexBaseIndex + nodePositions.Count;
            //                //                nodePositions.Add( new Vector4( position, Weight ) );
            //                //                nodeNormals.Add( normal );

            //                //                if ( i == 0 )
            //                //                {
            //                //                    // Only add this once, of course
            //                //                    batchTexCoords.Add( texCoords[ j ] );
            //                //                }

            //                //                // Stop looking if we've reached our vertex count
            //                //                if ( nodePositions.Count == batchVertexCount )
            //                //                    goto end;
            //                //            }
            //                //        }

            //                //        end:
            //                //        batch.NodeBatches.Add( new MeshType7NodeBatch()
            //                //        {
            //                //            NodeIndex = nodeIndex,
            //                //            Positions = nodePositions.ToArray(),
            //                //            Normals   = nodeNormals.ToArray()
            //                //        });
            //                //    }

            //                //    batch.TexCoords = batchTexCoords.ToArray();

            //                //    foreach ( var i in batchVertexIndexRemap )
            //                //        vertexIndexRemap.Add( i.Key, i.Value );

            //                //    Debug.Assert( batch.NodeBatches.Count > 0 );
            //                //    Debug.Assert( batch.NodeBatches.TrueForAll( x => x.VertexCount == batch.NodeBatches[ 0 ].VertexCount ) );
            //                //    batches.Add( batch );
            //                //    batchVertexBaseIndex += batchVertexCount;
            //                //}

            //                //var materialIndex = mesh.MaterialIndex;
            //                //var triangles = new Triangle[mesh.TriangleCount];
            //                //for ( var i = 0; i < mesh.Triangles.Length; i++ )
            //                //{
            //                //    ref var triangle = ref triangles[i];
            //                //    triangle.A = ( ushort )vertexIndexRemap[mesh.Triangles[i].A];
            //                //    triangle.B = ( ushort )vertexIndexRemap[mesh.Triangles[i].B];
            //                //    triangle.C = ( ushort )vertexIndexRemap[mesh.Triangles[i].C];
            //                //}

            //                //mesh = new MeshType7();
            //                //mesh.Batches.AddRange( batches );
            //                //mesh.Triangles = triangles;
            //                //mesh.MaterialIndex = materialIndex;
            //                //node.Geometry.Meshes[meshIndex] = mesh;

            //                writer.WriteLine( $"o node_{node.Name}_mesh_{meshIndex}" );
            //                foreach ( var triangle in mesh.Triangles )
            //                {
            //                    writer.WriteLine( "f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}", vertexBaseIndex + triangle.A + 1, vertexBaseIndex + triangle.B + 1, vertexBaseIndex + triangle.C + 1 );
            //                }

            //                vertexBaseIndex += mesh.VertexCount;
            //            }
            //        }
            //    }
            //}



            //modelPack.Save( @"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\model\field\player_a.PB" );


            //ReplaceModelTest();
            //return;
            //GenerateMaterialPresets();
            //return;
            //var modelPack = new ModelPack( @"..\..\..\..\Resources\player_a.PB" );
            //foreach ( var material in modelPack.Models[0].Materials )
            //{
            //    Console.WriteLine( MaterialPresetStore.GetPresetId( material ) );
            //}
            //return;
            ////for ( var i = 0; i < modelPack.TexturePack.Count; i++ )
            ////{
            ////    var texture = modelPack.TexturePack[ i ];
            ////    texture.GetBitmap().Save( $"player_a_{i}.png" );
            ////}

            //modelPack.Save( @"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\model\field\player_a.PB" );
            ////ReplaceModelTest();
            //OpenAndSaveModelPackBatchTest();
        }
예제 #7
0
        private static void ConvertAssimpModel()
        {
            switch (Options.OutputFormat)
            {
            case OutputFormat.PB:
            {
                if (Options.PackedModel.ReplaceInput == null)
                {
                    throw new Exception("You must specify a PB replacement input for conversion to PB");
                }

                var modelPack = new ModelPack();
                if (Options.PackedModel.ReplaceInput != null)
                {
                    modelPack.Load(Options.PackedModel.ReplaceInput);
                }

                if (!Options.Assimp.TreatInputAsAnimation)
                {
                    modelPack.Replace(Options.Input, Options.TmxScale, Options.Model.EnableMaterialOverlays, Options.Model.WeightedMeshType,
                                      Options.Model.UnweightedMeshType, Options.Model.MeshWeightLimit, Options.Model.BatchVertexLimit);
                }
                else
                {
                    var newMotion =
                        AssimpMotionImporter.Instance.Import(Options.Input,
                                                             new AssimpMotionImporter.Config
                        {
                            NodeIndexResolver = n => modelPack.Models[Options.PackedModel.ReplaceMotionModelIndex].Nodes.FindIndex(x => x.Name == n)
                        });

                    if (Options.PackedModel.ReplaceMotionIndex < 0 || (Options.PackedModel.ReplaceMotionIndex + 1) >
                        modelPack.MotionPacks[Options.PackedModel.ReplaceMotionPackIndex].Motions.Count)
                    {
                        modelPack.MotionPacks[Options.PackedModel.ReplaceMotionPackIndex].Motions[Options.PackedModel.ReplaceMotionIndex] = newMotion;
                    }
                }

                modelPack.Save(Options.Output);
            }
            break;

            case OutputFormat.F1:
            {
                var modelPack = new ModelPack();
                var model     = new Model();
                model.Nodes.Add(new Node {
                        Name = "model"
                    });
                modelPack.Models.Add(model);
                modelPack.Replace(Options.Input, Options.TmxScale, Options.Model.EnableMaterialOverlays,
                                  Options.Model.WeightedMeshType, Options.Model.UnweightedMeshType, Options.Model.MeshWeightLimit, Options.Model.BatchVertexLimit);

                var lb = new LBFileSystem();
                lb.Load(Options.Field.LbReplaceInput);

                var f1Handle = lb.GetHandle("F1");

                FieldScene f1;
                using (var stream = lb.OpenFile(f1Handle))
                    f1 = new FieldScene(stream, true);

                f1.Objects.RemoveAll(x => x.ResourceType == FieldObjectResourceType.Model);
                f1.Objects.Clear();
                f1.Objects.Add(new FieldObject()
                    {
                        Id = 0, Name = "model", Transform = new FieldObjectTransform(), Resource = modelPack.Models[0]
                    });

                lb.AddFile(f1Handle, f1.Save(), true, ConflictPolicy.Replace);

                if (modelPack.TexturePack != null)
                {
                    var tbHandle = lb.GetHandle("TBN");
                    lb.AddFile(tbHandle, modelPack.TexturePack.Save(), true, ConflictPolicy.Replace);
                }

                lb.Save(Options.Output);
            }
            break;

            default:
                throw new Exception("Unsupported output format");
            }
        }