Example #1
0
        private void SetBuffers()
        {
            float[] vertices = Meshes.SelectMany(x => x.Vertices).SelectMany(x => x.FloatArray()).ToArray();
            uint[]  elements = Meshes.SelectMany(x => x.Elements).Select(x => Convert.ToUInt32(x)).ToArray();

            int vertexOffset  = 0;
            int elementOffset = 0;

            foreach (var m in Meshes)
            {
                m.ElementOffset = elementOffset;
                m.ElementCount  = m.Elements.Count;
                elementOffset  += m.Elements.Count;

                for (int i = 0; i < m.Elements.Count; i++)
                {
                    elements[m.ElementOffset + i] += Convert.ToUInt32(vertexOffset);
                }

                vertexOffset += m.Vertices.Count;
            }

            GL.BindVertexArray(vertexArrayObject);

            vertexBufferId = GL.GenBuffer();
            GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferId);
            GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);

            elementBufferId = GL.GenBuffer();
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferId);
            GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(elements.Length * sizeof(uint)), elements, BufferUsageHint.StaticDraw);
        }
        public void RecomputeVertexNormals()
        {
            var verts = Meshes.SelectMany(m => m.Vertices).Select(v => v.Position).ToList();

            var closeVertices = new List <CloseVertex>();

            foreach (var vert in verts)
            {
                if (!closeVertices.Where(cv => cv == vert).Any())
                {
                    closeVertices.Add(new CloseVertex()
                    {
                        Position = vert
                    });
                }
            }

            // Get all mesh all triangles
            // Compute their normals
            // They reference close verts to average out the normals
            // Then individual verts reference close verts
            foreach (var mesh in Meshes)
            {
                foreach (var triangle in mesh.Triangles)
                {
                    var v1 = mesh.Vertices[triangle.v1].Position;
                    var v2 = mesh.Vertices[triangle.v2].Position;
                    var v3 = mesh.Vertices[triangle.v3].Position;

                    var normal = CalcFaceNormal(mesh, triangle);

                    var cv1 = closeVertices.Where(cv => cv == v1).Single();
                    var cv2 = closeVertices.Where(cv => cv == v2).Single();
                    var cv3 = closeVertices.Where(cv => cv == v3).Single();

                    cv1.NormalSum += normal;
                    cv2.NormalSum += normal;
                    cv3.NormalSum += normal;
                }
            }


            foreach (var mesh in Meshes)
            {
                for (var v = 0; v < mesh.Vertices.Count; v++)
                {
                    var vertex = mesh.Vertices[v];

                    var cVertex = closeVertices.Where(cv => cv == vertex.Position).Single();

                    var len = Math.Sqrt(cVertex.NormalSum.X * cVertex.NormalSum.X + cVertex.NormalSum.Y * cVertex.NormalSum.Y + cVertex.NormalSum.Z * cVertex.NormalSum.Z);

                    var vertexNormal = new Vector3(cVertex.NormalSum / (float)len);

                    mesh.Vertices[v].Normal = vertexNormal;
                }
            }
        }
Example #3
0
        private void UpdateBoundingSphere()
        {
            IEnumerable <GcmfTriangleStrip> allTriangleStrip = Meshes.SelectMany(
                m => m.Obj1StripsCcw.Union(m.Obj1StripsCw).Union(m.Obj2StripsCcw).Union(m.Obj2StripsCw));
            IEnumerable <GcmfVertex> allVertices        = allTriangleStrip.SelectMany(ts => ts);
            IEnumerable <Vector3>    allVertexPositions = allVertices.Select(v => v.Position);

            BoundingSphere boundingSphere = BoundingSphere.FromPoints(allVertexPositions);

            BoundingSphereCenter = boundingSphere.Center;
            BoundingSphereRadius = boundingSphere.Radius;
        }
Example #4
0
        public void Save(Stream destination, ObjectDatabase objectDatabase, TextureDatabase textureDatabase,
                         BoneDatabase boneDatabase, bool leaveOpen = false)
        {
            if (objectDatabase != null)
            {
                foreach (var mesh in Meshes)
                {
                    mesh.Id = objectDatabase.GetMesh(mesh.Name)?.Id ?? mesh.Id;
                }
            }

            if (boneDatabase != null)
            {
                string fileName = destination is FileStream fileStream
                    ? Path.GetFileName(fileStream.Name)
                    : string.Empty;

                var skeletonEntry =
                    boneDatabase.Skeletons.FirstOrDefault(x =>
                                                          fileName.StartsWith(x.Name, StringComparison.OrdinalIgnoreCase)) ??
                    boneDatabase.Skeletons.FirstOrDefault(x =>
                                                          x.Name.Equals("CMN", StringComparison.OrdinalIgnoreCase)) ??
                    boneDatabase.Skeletons[0];

                if (skeletonEntry != null)
                {
                    foreach (var skin in Meshes.Where(x => x.Skin != null).Select(x => x.Skin))
                    {
                        foreach (var bone in skin.Bones)
                        {
                            int index = skin.ExData?.BoneNames?.FindIndex(x =>
                                                                          x.Equals(bone.Name, StringComparison.OrdinalIgnoreCase)) ?? -1;

                            if (index == -1)
                            {
                                index = skeletonEntry.BoneNames1.FindIndex(x =>
                                                                           x.Equals(bone.Name, StringComparison.OrdinalIgnoreCase));
                            }
                            else
                            {
                                index = 0x8000 | index;
                            }

                            if (index == -1)
                            {
                                continue;
                            }

                            foreach (var childBone in skin.Bones.Where(x => x.ParentId == bone.Id))
                            {
                                childBone.ParentId = index;
                            }

                            bone.Id = index;
                        }
                    }
                }
            }

            if (textureDatabase != null && TextureSet != null)
            {
                int id           = textureDatabase.Textures.Max(x => x.Id) + 1;
                var idDictionary = new Dictionary <int, int>(TextureSet.Textures.Count);

                foreach (var texture in TextureSet.Textures)
                {
                    var textureEntry = !string.IsNullOrEmpty(texture.Name)
                        ? textureDatabase.GetTexture(texture.Name)
                        : textureDatabase.GetTexture(texture.Id);

                    if (textureEntry == null)
                    {
                        textureDatabase.Textures.Add(
                            textureEntry = new TextureEntry
                        {
                            Name = texture.Name,
                            Id   = id++
                        });

                        if (string.IsNullOrEmpty(textureEntry.Name))
                        {
                            textureEntry.Name = $"Unnamed {textureEntry.Id}";
                        }
                    }
                    idDictionary[texture.Id] = textureEntry.Id;

                    texture.Name = textureEntry.Name;
                    texture.Id   = textureEntry.Id;
                }

                foreach (var materialTexture in Meshes.SelectMany(x => x.Materials)
                         .SelectMany(x => x.MaterialTextures))
                {
                    if (idDictionary.TryGetValue(materialTexture.TextureId, out id))
                    {
                        materialTexture.TextureId = id;
                    }
                }

                TextureIds.Clear();
                TextureIds.AddRange(TextureSet.Textures.Select(x => x.Id));
            }

            Save(destination, leaveOpen);
        }
Example #5
0
 public Mesh ToUnityMesh()
 {
     return(TriangleMesh.ToUnityMesh(Meshes.SelectMany(mesh => mesh.TriangleMeshes)));
 }
Example #6
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);
        }