예제 #1
0
        private static void HandleFile(string path)
        {
            if (Directory.Exists(path))
            {
                Console.WriteLine($"Packing {Path.GetFileName(path)}...");
                using var archive = ArchiveFile.FromDirectory(path);
                if (File.Exists(path + ".par") && !File.Exists(path + ".par.bak"))
                {
                    File.Copy(path + ".par", path + ".par.bak");
                }

                archive.Save(File.OpenWrite(path + ".par"));
            }
            else
            {
                switch (Path.GetExtension(path))
                {
                case ".par":
                    Console.WriteLine($"Extracting {Path.GetFileName(path)}");
                    using (var archive = ArchiveFile.FromFile(path))
                    {
                        archive.Extract(Path.ChangeExtension(path, null));
                    }

                    break;

                case ".gmd":
                    Console.WriteLine($"Exporting {Path.GetFileName(path)}");
                    var gmdFile = GmdFile.FromFile(path);
                    var mesh    = YakuzaMesh.FromGmdFile(gmdFile);
                    mesh.SaveToGltf2(Path.ChangeExtension(path, ".glb"), FindTextureFolder(path));
                    break;
                }
            }
        }
예제 #2
0
        public static YakuzaMesh FromGmdFile(GmdFile GmdFile)
        {
            var mesh = new YakuzaMesh();

            mesh.LoadGmdFile(GmdFile);
            return(mesh);
        }
예제 #3
0
        private Bone LoadBone(GmdFile.BoneTransform boneTransform, Bone parent, GmdFile file, Bone[] boneTable)
        {
            var bone = new Bone();

            bone.Id       = boneTransform.BoneNo;
            bone.Name     = file.BoneNames[boneTransform.BoneNameIndex].ToString();
            bone.Position = boneTransform.LocalPosition;
            bone.Rotation = boneTransform.LocalRotation;
            bone.Scale    = boneTransform.Scale;
            bone.Parent   = parent;
            boneTable[boneTransform.BoneNo] = bone;

            bone.Children.AddRange(GmdUtils.GetChildren(boneTransform, file.BoneTransforms).Select(bt => LoadBone(bt, bone, file, boneTable)));

            return(bone);
        }
예제 #4
0
        static void Main(string[] args)
        {
            var ddsPath = @"D:\Program Files (x86)\Steam\steamapps\common\Yakuza Kiwami 2\data\chara_unpack\lexus2\dds";

            using var archiveIn  = ArchiveFile.FromFile(@"D:\Program Files (x86)\Steam\steamapps\common\Yakuza Kiwami 2\data\chara_original.par");
            using var archiveOut = File.OpenWrite(@"D:\Program Files (x86)\Steam\steamapps\common\Yakuza Kiwami 2\data\chara.par");

            var fileName = "c_am_kiryu.gmd";
            // var fileName = "c_am_dummy_01.gmd";
            // var fileName = "c_aw_haruka.gmd";
            // var fileName = "c_am_S03_soutenboripl.gmd";


            var kiryu = archiveIn.Find(fileName);

            using var tempFile = new MemoryStream();
            archiveIn.Read(kiryu).CopyTo(tempFile);
            tempFile.Seek(0, SeekOrigin.Begin);

            var gmd  = GmdFile.FromStream(tempFile);
            var mesh = YakuzaMesh.FromGmdFile(gmd);

            mesh.SaveToGltf2("mesh.glb", ddsPath);
            if (Directory.Exists("textures"))
            {
                Directory.Delete("textures", true);
            }

            var mesh1 = YakuzaMesh.FromGltf2("mesh_edited.glb", "textures");

            foreach (var file in Directory.EnumerateFiles("textures"))
            {
                Console.WriteLine($"Adding texture: {Path.GetFileName(file)}");
                archiveIn.AddFile("lexus2\\dds\\" + Path.GetFileName(file), File.ReadAllBytes(file));
            }

            var gmd2 = mesh1.ToGmdFile();

            tempFile.Seek(0, SeekOrigin.Begin);
            gmd2.Write(tempFile);


            tempFile.Seek(0, SeekOrigin.Begin);
            archiveIn.ReplaceFile(fileName, tempFile.ToArray());

            archiveIn.Save(archiveOut, Endianness.Big);
        }
예제 #5
0
        public static YakuzaMesh FromGmdStream(Stream stream)
        {
            var gmd = GmdFile.FromStream(stream);

            return(FromGmdFile(gmd));
        }
예제 #6
0
 public static YakuzaMesh FromArchive(string name, ArchiveFile archive)
 {
     return(FromGmdFile(GmdFile.FromArchive(name, archive)));
 }
예제 #7
0
        private void LoadGmdFile(GmdFile gmdFile)
        {
            Name = gmdFile.Name;

            Textures = gmdFile.Textures.Select(tex => tex.Name).ToArray();

            Materials = gmdFile.Materials.Select(mat =>
            {
                return(new Material
                {
                    Id = mat.Id,
                    Shader = gmdFile.Shaders[mat.ShaderIndex].ToString(),
                    Textures = mat.TextureIndices.Select(texIdx =>
                    {
                        if (texIdx >= 0 && texIdx < Textures.Length)
                        {
                            return Textures[texIdx];
                        }

                        return null;
                    }).ToArray()
                });
            }).ToArray();

            var bones = new Bone[gmdFile.BoneTransforms.Length];

            foreach (var bt in gmdFile.BoneTransforms)
            {
                if (GmdUtils.GetParentBone(bt, gmdFile.BoneTransforms) == null)
                {
                    LoadBone(bt, null, gmdFile, bones);
                }
            }

            Bones = bones.ToArray();


            var nameList = new List <string>();
            var meshes   = new List <Mesh>();

            foreach (var gmdMesh in gmdFile.Meshes)
            {
                var mesh = new Mesh();
                meshes.Add(mesh);

                // Console.WriteLine($"------------");

                foreach (var gmdSub in gmdFile.Submeshes.Where(s => s.MeshIndex == gmdMesh.MeshId))
                {
                    var submesh = new Submesh();
                    mesh.Submeshes.Add(submesh);

                    submesh.Id        = gmdSub.Id;
                    submesh.Name      = GetSubmeshName(Bones[gmdSub.BoneNo].Name, nameList);
                    submesh.Transform = Bones[gmdSub.BoneNo].WorldMatrix;
                    submesh.Material  = Materials[gmdSub.MaterialIndex];
                    submesh.Vertices  = ReadVertices(gmdSub, gmdMesh, gmdFile);
                    submesh.Triangles = new int[gmdSub.IndicesCount / 3, 3];

                    // Console.WriteLine(submesh.Name.PadRight(25, ' ')
                    //                   + submesh.Material.Shader.PadRight(25, ' ')
                    //                   + $"{gmdMesh.HasFlag1} {gmdMesh.HasFlag2} {gmdMesh.HasFlag3}");

                    var offset = gmdSub.IndicesOffset;
                    for (int i = 0; i < gmdSub.IndicesCount / 3; i++)
                    {
                        submesh.Triangles[i, 0] = gmdFile.Indices[offset + i * 3].Value - gmdSub.BufferOffset2;
                        submesh.Triangles[i, 1] = gmdFile.Indices[offset + i * 3 + 1].Value - gmdSub.BufferOffset2;
                        submesh.Triangles[i, 2] = gmdFile.Indices[offset + i * 3 + 2].Value - gmdSub.BufferOffset2;
                    }
                }
            }

            Meshes = meshes.ToArray();
        }
예제 #8
0
        private Vertex[] ReadVertices(GmdFile.Submesh submesh, GmdFile.Mesh mesh, GmdFile file)
        {
            var vertices  = new Vertex[submesh.VertexCount];
            var meshIndex = Array.IndexOf(file.Meshes, mesh);

            using var memoryStream = new MemoryStream(file.VertexBuffers[meshIndex]);
            using var bs           = new BinaryReader(memoryStream);

            bs.BaseStream.Seek((submesh.BufferOffset1 + submesh.BufferOffset2) * mesh.Stride, SeekOrigin.Begin);

            for (int j = 0; j < submesh.VertexCount; j++)
            {
                var v = new Vertex();
                v.Position = GmdUtils.ReadVector3(bs);
                if (mesh.HasBones && file.BoneIndices.Length > 0)
                {
                    v.BoneWeights = new[]
                    {
                        bs.ReadByteAsFloat(),
                            bs.ReadByteAsFloat(),
                            bs.ReadByteAsFloat(),
                            bs.ReadByteAsFloat()
                    };

                    v.BoneIndices = new[]
                    {
                        file.BoneIndices[bs.ReadByte() + submesh.BoneIndexOffset + 1].Value,
                        file.BoneIndices[bs.ReadByte() + submesh.BoneIndexOffset + 1].Value,
                        file.BoneIndices[bs.ReadByte() + submesh.BoneIndexOffset + 1].Value,
                        file.BoneIndices[bs.ReadByte() + submesh.BoneIndexOffset + 1].Value
                    };
                }

                v.Normal = GmdUtils.ReadNormal(bs);
                bs.ReadByte();

                if (mesh.HasFlag1)
                {
                    // var a = bs.ReadByteAsFloat();
                    // var b = bs.ReadByteAsFloat();
                    // var c = bs.ReadByteAsFloat();
                    // var d = bs.ReadByteAsFloat();
                    var val = bs.ReadInt32();
                    // Console.WriteLine($"{a:0.00} / {b:0.00} / {c:0.00} / {d:0.00}");
                    // bs.ReadInt32();
                }

                if (mesh.HasFlag2)
                {
                    bs.ReadInt32();
                }

                if (mesh.HasFlag3)
                {
                    bs.ReadInt32();
                }

                for (int l = 0; l < mesh.UvLayers; l++)
                {
                    var uvs = new Vector2(Half.ToHalf(bs.ReadUInt16()), 1 - Half.ToHalf(bs.ReadUInt16()));
                    switch (l)
                    {
                    case 0:
                        v.Uv0 = uvs;
                        break;

                    case 1:
                        v.Uv1 = uvs;
                        break;

                    case 2:
                        v.Uv2 = uvs;
                        break;

                    case 3:
                        v.Uv3 = uvs;
                        break;

                    default:
                        Console.Error.WriteLine("Too many UV channels!");
                        break;
                    }
                }

                vertices[j] = v;
            }

            return(vertices);
        }
예제 #9
0
        public GmdFile ToGmdFile()
        {
            var file = new GmdFile();

            file.Name = Name;
            // TEXTURES

            var textures = Textures.Concat(new string[] { "_dummy_rd", "dummy_nmap", "dummy_black", "dummy_gray", "dummy_white", "default_z", "noise" })
                           .Distinct().ToArray();

            file.Textures = textures
                            .Select(GmdFile.HashedName.FromString)
                            .ToArray();

            var shaders     = Materials.Select(mat => mat.Shader).Distinct().ToArray();
            var hlSubmeshes = Meshes.SelectMany(m => m.Submeshes).OrderBy(sm => sm.Id).ToArray();

            // MATERIALS
            file.Materials = Materials.Select(mat =>
            {
                var material = new GmdFile.Material()
                {
                    Id             = mat.Id,
                    TextureIndices =
                        mat.Textures.Select(tex => (int)(ushort)Array.IndexOf(textures, tex))
                        .Concat(Enumerable.Repeat((int)ushort.MaxValue, 8 - mat.Textures.Length)).ToArray(),
                    ShaderIndex  = (uint)Array.IndexOf(shaders, mat.Shader),
                    SubmeshIndex = (uint)Array.FindIndex(hlSubmeshes, m => m.Material == mat)
                };

                /*
                 * 3 => rd (sd_o1dzt_m2dzt) / tr (skin) / dummy_white
                 *  4 => rm / default_z [can be default_z, strange things happen when null]
                 *  5 => rt / noise [can be noise, too smooth when null]
                 *  6 => rs [can be null]
                 *  7 =>
                 */

                material.TextureIndices[0] = material.TextureIndices[0] >= 255 ? Array.IndexOf(textures, "dummy_black") : material.TextureIndices[0];
                material.TextureIndices[1] = material.TextureIndices[1] >= 255 ? Array.IndexOf(textures, "default_z") : material.TextureIndices[1];
                material.TextureIndices[2] = material.TextureIndices[2] >= 255 ? Array.IndexOf(textures, "dummy_nmap") : material.TextureIndices[2];
                material.TextureIndices[3] = material.TextureIndices[3] >= 255 ? Array.IndexOf(textures, "dummy_white") : material.TextureIndices[3];
                material.TextureIndices[4] = material.TextureIndices[4] >= 255 ? Array.IndexOf(textures, "default_z") : material.TextureIndices[4];
                material.TextureIndices[5] = material.TextureIndices[5] >= 255 ? Array.IndexOf(textures, "noise") : material.TextureIndices[5];
                material.TextureIndices[6] = material.TextureIndices[6] >= 255 ? ushort.MaxValue : material.TextureIndices[6]; //ushort.MaxValue;
                material.TextureIndices[7] = material.TextureIndices[7] >= 255 ? ushort.MaxValue : material.TextureIndices[7]; //ushort.MaxValue;
                // ushort.MaxValue

                material.Initialize(mat.Shader == GmdUtils.TRANSPARENCY_MAT);

                return(material);
            }).ToArray();

            // SHADERS
            file.Shaders = shaders.Select(shader => GmdFile.HashedName.FromString(shader)).ToArray();

            // MESHES
            var meshes        = new List <GmdFile.Mesh>();
            var vertexBuffers = new List <byte[]>();
            var submeshes     = new List <GmdFile.Submesh>();
            var indices       = new List <GmdFile.Index>();
            var boneIndices   = new List <GmdFile.BoneIndex>();

            for (int i = 0; i < Meshes.Length; i++)
            {
                var mesh        = Meshes[i];
                var gmdMesh     = new GmdFile.Mesh();
                var firstVertex = mesh.Submeshes.First().Vertices.First();

                gmdMesh.Initialize();
                gmdMesh.MeshId    = i;
                gmdMesh.Count     = mesh.Submeshes.Sum(m => m.Vertices.Length);
                gmdMesh.Offset    = vertexBuffers.Sum(b => b.Length);
                gmdMesh.UvLayers  = firstVertex.UvLayerCount;
                gmdMesh.HasBones  = firstVertex.BoneIndices != null;
                gmdMesh.FlagCount = GmdUtils.GetFlagCount(mesh.Submeshes.First().Material.Shader);

                using var buffer = new MemoryStream();
                using var writer = new BinaryWriter(buffer);

                Console.WriteLine("m" + i);
                int vertexCount = 0;
                for (int j = 0; j < mesh.Submeshes.Count; j++)
                {
                    var submesh       = mesh.Submeshes[j];
                    var gmdSubmesh    = new GmdFile.Submesh();
                    var boneIndexList = submesh.Vertices.SelectMany(v => v.BoneIndices ?? Enumerable.Empty <int>()).Distinct().ToList();

                    gmdSubmesh.Id              = Array.IndexOf(hlSubmeshes, submesh);
                    gmdSubmesh.MeshIndex       = i;
                    gmdSubmesh.IndicesCount    = submesh.Triangles.GetLength(0) * 3;
                    gmdSubmesh.IndicesOffset   = indices.Count;
                    gmdSubmesh.VertexCount     = submesh.Vertices.Length;
                    gmdSubmesh.MaterialIndex   = (int)submesh.Material.Id;
                    gmdSubmesh.BufferOffset2   = vertexCount;
                    gmdSubmesh.BoneIndexOffset = boneIndices.Count;
                    gmdSubmesh.BoneIndexCount  = boneIndexList.Count;

                    gmdMesh.Stride = WriteVertices(writer, submesh, gmdMesh.FlagCount, boneIndexList);

                    boneIndexList.Insert(0, gmdSubmesh.BoneIndexCount); // Expects count in index list
                    vertexCount += submesh.Vertices.Length;

                    // Fill in indices
                    for (int y = 0; y < submesh.Triangles.GetLength(0); y++)
                    {
                        indices.Add(new GmdFile.Index()
                        {
                            Value = submesh.Triangles[y, 0] + gmdSubmesh.BufferOffset2
                        });
                        indices.Add(new GmdFile.Index()
                        {
                            Value = submesh.Triangles[y, 1] + gmdSubmesh.BufferOffset2
                        });
                        indices.Add(new GmdFile.Index()
                        {
                            Value = submesh.Triangles[y, 2] + gmdSubmesh.BufferOffset2
                        });
                    }

                    boneIndices.AddRange(boneIndexList.Select(idx => new GmdFile.BoneIndex()
                    {
                        Value = idx
                    }));

                    submeshes.Add(gmdSubmesh);
                }

                gmdMesh.Size = (int)buffer.Length;
                vertexBuffers.Add(buffer.ToArray());

                meshes.Add(gmdMesh);
            }

            file.Indices        = indices.ToArray();
            file.Meshes         = meshes.ToArray();
            file.Submeshes      = submeshes.OrderBy(sm => sm.Id).ToArray();
            file.VertexBuffers  = vertexBuffers.ToArray();
            file.BoneIndices    = boneIndices.ToArray();
            file.BoneNames      = Bones.Select(b => GmdFile.HashedName.FromString(b.Name)).ToArray();
            file.BoneTransforms = Bones.Select(bone =>
            {
                var bt           = new GmdFile.BoneTransform();
                bt.Position      = bone.WorldMatrix.Translation;
                bt.LocalPosition = bone.Position;
                bt.LocalRotation = bone.Rotation;
                bt.Scale         = bone.Scale;
                bt.BoneNo        = bt.BoneNo2 = bone.Id;
                bt.BoneNameIndex = bone.Id;

                bt.TransformIndex   = -1;
                bt.NextSiblingIndex = -1;
                bt.NextChildIndex   = -1;
                bt.Footer           = new byte[16];

                if (bone.Name.Contains("[l0]"))
                {
                    bt.TransformIndex = 0;
                    bt.NodeType       = GmdFile.BoneTransform.NODE_TYPE_TRANSFORM;
                }

                // If bone has children, set the nextChildIndex idx
                if (bone.Children.Count > 0)
                {
                    bt.NextChildIndex = bone.Children[0].Id;
                }

                // If bone has another sibling that comes after itself, set NextSiblingIndex
                if (bone.Parent != null)
                {
                    var childIdx = bone.Parent.Children.IndexOf(bone);
                    if (childIdx >= 0 && childIdx + 1 < bone.Parent.Children.Count)
                    {
                        bt.NextSiblingIndex = bone.Parent.Children[childIdx + 1].Id;
                    }
                }

                return(bt);
            }).ToArray();


            return(file);
        }