public static void EvaluateNormals(ModelMeshData mesh)
        {
            Vector3[] normals = new Vector3[mesh.Vertices.Count];
             for (int i = 0; i != mesh.Vertices.Count; ++i )
            normals[i] = Vector3.Zero;

             Action<int, int, int, int> ProcessTriangle = delegate(int partIdx, int idx1, int idx2, int idx3)
             {
            List<short> indices = mesh.MeshParts[partIdx].Indices;
            int[] idx = { indices[idx1], indices[idx2], indices[idx3] };
            Vector3 side1 = mesh.Vertices[idx[1]] - mesh.Vertices[idx[0]];
            Vector3 side2 = mesh.Vertices[idx[2]] - mesh.Vertices[idx[0]];
            Vector3 norm = Vector3.Cross(side1, side2);
            norm.Normalize();
            for (int i = 0 ; i != 3; ++i)
               normals[idx[i]] += norm;
             };

             if (mesh.TriangleStrip)
            for (int j = 0; j != mesh.MeshParts.Count; ++j )
               for (int i = 2; i < mesh.MeshParts[j].Indices.Count; ++i)
                  ProcessTriangle(j, i - 2, i - 1, i);
             else
            for (int j = 0; j != mesh.MeshParts.Count; ++j)
               for (int i = 0; i < mesh.MeshParts[j].Indices.Count; i += 3)
                  ProcessTriangle(j, i, i + 1, i + 2);

             for (int i = 0; i != normals.Length; ++i)
             {
            normals[i].Normalize();
            normals[i] = normals[i];
             }

             mesh.Normals = new List<Vector3>(normals);
        }
        private void ParseStringSection(int size, SectionType parentType)
        {
            byte[] data = input.ReadBytes(size);
            if (parentType == SectionType.Texture)
            {
                int len = Array.IndexOf(data, (byte)0);
                if (len == -1)
                {
                    len = data.Length;
                }
                if (len == 0)
                {
                    return;
                }

                string textureName = Encoding.ASCII.GetString(data, 0, len);

                if (texturesFolder != null)
                {
                    Texture2D texture = TexturesStorage.Instance.GetTexture(textureName, texturesFolder);
                    if (texture != null)
                    {
                        ModelMeshData mesh     = modelData.Meshes[modelData.Meshes.Count - 1];
                        Material      material = mesh.Materials[mesh.Materials.Count - 1];
                        material.Texture = texture;
                    }
                }
            }
        }
        /// <summary>
        /// Обрабатывает секцию MaterialSplit (она же Bin Mesh PLG)
        /// Насколько я понял, эта секция нужна, когда отдельным кускам меша присваивается разный метариел (текстура),
        /// либо когда треугольники перечисляются не в виде TriangleList, а в виде TriangleStrip.
        ///
        /// Перезаписывает данные в последнем добавленном меше в modelData
        /// </summary>
        private void ParseMaterialSplit(int sectionSize)
        {
            int sectionEnd = (int)input.BaseStream.Position + sectionSize;

            // ParseMaterialSplit вызывается всегда после ParseGeometry, которая добавляет новый mesh в modelData
            ModelMeshData mesh = modelData.Meshes[modelData.Meshes.Count - 1];

            int triangleStrip = input.ReadInt32();
            int splitCount    = input.ReadInt32();

            mesh.SumIndicesCount = input.ReadInt32();

            mesh.TriangleStrip = triangleStrip != 0;

            mesh.MeshParts.Clear(); // перезаписываем данные о треугольниках

            for (int j = 0; j < splitCount; ++j)
            {
                int localIndicesCount = input.ReadInt32();
                int materialIdx       = input.ReadInt32();

                ModelMeshPartData meshPart = new ModelMeshPartData(localIndicesCount, materialIdx);
                for (int i = 0; i != localIndicesCount; ++i)
                {
                    meshPart.Indices.Add((short)input.ReadInt32());
                }

                mesh.MeshParts.Add(meshPart);
            }
        }
 private void FillColors(ModelMeshData mesh, int verticesCount)
 {
     mesh.Colors = new List <Color>(verticesCount);
     for (int i = 0; i != verticesCount; ++i)
     {
         mesh.Colors.Add(new Color(0, 0, 0, 1));
     }
 }
 private static VertexBuffer CreateTexturedVertexBuffer(ModelMeshData mesh)
 {
     var vertices = new VertexPositionColorTexture[mesh.Vertices.Count];
      for (var i = 0; i != mesh.Vertices.Count; ++i)
     vertices[i] = new VertexPositionColorTexture(mesh.Vertices[i], mesh.Colors[i], mesh.TextureCoords[i]);
      VertexBuffer vertexBuffer = new VertexBuffer(GraphicsDeviceHolder.Device,
     mesh.Vertices.Count * VertexPositionColorTexture.SizeInBytes, BufferUsage.WriteOnly);
      vertexBuffer.SetData(vertices);
      return vertexBuffer;
 }
        private void ReadTextureCoords(ModelMeshData mesh, int verticesCount)
        {
            mesh.TextureCoords = new List <Vector2>(verticesCount);
            for (var i = 0; i != verticesCount; ++i)
            {
                float x = input.ReadSingle();
                float y = input.ReadSingle();

                mesh.TextureCoords.Add(new Vector2(x, y));
            }
        }
        private void ReadNormals(ModelMeshData mesh, int verticesCount)
        {
            mesh.Normals = new List <Vector3>(verticesCount);

            for (var i = 0; i != verticesCount; ++i)
            {
                var x = input.ReadSingle();
                var y = input.ReadSingle(); // y and z coords are exchanged because of different coordinate system
                var z = input.ReadSingle();
                mesh.Normals.Add(new Vector3(x, z, -y));
            }
        }
 private void ReadColors(ModelMeshData mesh, int verticesCount)
 {
     mesh.Colors = new List <Color>(verticesCount);
     for (int i = 0; i != verticesCount; ++i)
     {
         byte r = input.ReadByte();
         byte g = input.ReadByte();
         byte b = input.ReadByte();
         byte a = input.ReadByte();
         mesh.Colors.Add(new Color(r, g, b, a));
     }
 }
        /// <summary>
        /// Обрабатывает секцию Geometry
        /// Считывает вершины, треугольники (индексы вершин), нормали, текстурные координаты.
        /// </summary>
        private void ParseGeometry(DffVersion version)
        {
            ModelMeshData mesh = new ModelMeshData();

            GeometrySectionFlags flags = (GeometrySectionFlags)input.ReadInt16();

            input.BaseStream.Seek(sizeof(short), SeekOrigin.Current); // unknown

            int trianglesCount = input.ReadInt32();
            int verticesCount  = input.ReadInt32();

            input.BaseStream.Seek(sizeof(int), SeekOrigin.Current); // morphTargetCount aka frameCount

            if (version < DffVersion.GTA_VC_2)
            {
                // geometry has lighting data. Ignoring it.
                // TODO :: we can use it for rendering!!!
                input.BaseStream.Seek(12, SeekOrigin.Current);
            }

            if ((flags & GeometrySectionFlags.MultipleTextureCoords) != GeometrySectionFlags.None)
            {
                Log.Instance.Print("Multiple TexCoords sets are provided but used only the first of it!", MessageType.Warning);
            }

            if ((flags & GeometrySectionFlags.HasColorInfo) != GeometrySectionFlags.None)
            {
                ReadColors(mesh, verticesCount);
            }
            else
            {
                FillColors(mesh, verticesCount);
            }

            if ((flags & GeometrySectionFlags.HasTextureCoords) != GeometrySectionFlags.None)
            {
                ReadTextureCoords(mesh, verticesCount);
            }

            ReadTriangles(mesh, trianglesCount);

            input.BaseStream.Seek(4 * sizeof(float), SeekOrigin.Current); // ignoring bounding sphere (x, y, z, radius)
            input.BaseStream.Seek(2 * sizeof(int), SeekOrigin.Current);   // hasPosition, hasNormal (not used)

            ReadVertices(mesh, verticesCount);

            if ((flags & GeometrySectionFlags.HasNormalsInfo) != GeometrySectionFlags.None)
            {
                ReadNormals(mesh, verticesCount);
            }

            modelData.Meshes.Add(mesh);
        }
Ejemplo n.º 10
0
        private static VertexBuffer CreateColoredVertexBuffer(ModelMeshData mesh)
        {
            var vertices = new VertexPositionColor[mesh.Vertices.Count];

            for (var i = 0; i != mesh.Vertices.Count; ++i)
            {
                vertices[i] = new VertexPositionColor(mesh.Vertices[i], mesh.Colors[i]);
            }
            var vertexBuffer = new VertexBuffer(GraphicsDeviceHolder.Device,
                                                mesh.Vertices.Count * VertexPositionColor.SizeInBytes, BufferUsage.WriteOnly);

            vertexBuffer.SetData(vertices);
            return(vertexBuffer);
        }
Ejemplo n.º 11
0
        private void ReadTriangles(ModelMeshData mesh, int trianglesCount)
        {
            ModelMeshPartData meshPart = new ModelMeshPartData(trianglesCount * 3, 0);

            mesh.SumIndicesCount = trianglesCount * 3;

            for (var i = 0; i != trianglesCount; ++i)
            {
                meshPart.Indices.Add(input.ReadInt16());
                meshPart.Indices.Add(input.ReadInt16());
                input.BaseStream.Seek(sizeof(short), SeekOrigin.Current); // skip index flags
                meshPart.Indices.Add(input.ReadInt16());
            }

            mesh.MeshParts = new List <ModelMeshPartData>();
            mesh.MeshParts.Add(meshPart);
        }
Ejemplo n.º 12
0
        private static ModelMesh3D CreateModelMesh(ModelMeshData mesh)
        {
            bool textured     = mesh.TextureCoords != null;
            var  vertexBuffer = textured ? CreateTexturedVertexBuffer(mesh) : CreateColoredVertexBuffer(mesh);

            List <ModelMeshPart3D> meshParts3d;
            var indexBuffer = CreateIndexBuffer(mesh, out meshParts3d);

            return(new ModelMesh3D(
                       new VertexDeclaration(GraphicsDeviceHolder.Device, textured? VertexPositionColorTexture.VertexElements : VertexPositionColor.VertexElements),
                       vertexBuffer,
                       indexBuffer,
                       mesh.TriangleStrip,
                       textured? VertexPositionColorTexture.SizeInBytes : VertexPositionColor.SizeInBytes,
                       mesh.Materials,
                       meshParts3d
                       ));
        }
        private static ModelMesh3D CreateModelMesh(ModelMeshData mesh)
        {
            bool textured = mesh.TextureCoords != null;
             var vertexBuffer = textured ? CreateTexturedVertexBuffer(mesh) : CreateColoredVertexBuffer(mesh);

             List<ModelMeshPart3D> meshParts3d;
             var indexBuffer = CreateIndexBuffer(mesh, out meshParts3d);

             return new ModelMesh3D(
            new VertexDeclaration(GraphicsDeviceHolder.Device, textured? VertexPositionColorTexture.VertexElements : VertexPositionColor.VertexElements),
               vertexBuffer,
               indexBuffer,
               mesh.TriangleStrip,
               textured? VertexPositionColorTexture.SizeInBytes : VertexPositionColor.SizeInBytes,
               mesh.Materials,
               meshParts3d
            );
        }
        private static IndexBuffer CreateIndexBuffer(ModelMeshData mesh, out List<ModelMeshPart3D> meshParts3d)
        {
            var indexBuffer = new IndexBuffer(GraphicsDeviceHolder.Device, mesh.SumIndicesCount * sizeof(short),
            BufferUsage.WriteOnly, IndexElementSize.SixteenBits);

             meshParts3d = new List<ModelMeshPart3D>();
             int offset = 0;
             foreach (ModelMeshPartData part in mesh.MeshParts)
             {
            indexBuffer.SetData(offset * sizeof(short), part.Indices.ToArray(), 0, part.Indices.Count);
            meshParts3d.Add(new ModelMeshPart3D(offset, mesh.TriangleStrip ? part.Indices.Count - 2 : part.Indices.Count / 3, part.MaterialId));
            offset += part.Indices.Count;
             }

             if (offset != mesh.SumIndicesCount)
            Utils.TerminateWithError("Incorrect total indices amount!");

             return indexBuffer;
        }
Ejemplo n.º 15
0
        private void ParseMaterial(int sectionSize)
        {
            input.BaseStream.Seek(4, SeekOrigin.Current); // unknown data
            byte[] color = input.ReadBytes(4);
            input.BaseStream.Seek(4, SeekOrigin.Current); // unknown data
            int textureCount = input.ReadInt32();

            input.BaseStream.Seek(12, SeekOrigin.Current); // unknown data

            if (textureCount != 0 && textureCount != 1)
            {
                Log.Instance.Print("Material section: unexpected TexturesCount value: " + textureCount);
            }

            ModelMeshData mesh = modelData.Meshes[modelData.Meshes.Count - 1];

            mesh.Materials.Add(new Material()
            {
                Color = new Color(color[0], color[1], color[2], color[3])
            });
        }
Ejemplo n.º 16
0
        private static IndexBuffer CreateIndexBuffer(ModelMeshData mesh, out List <ModelMeshPart3D> meshParts3d)
        {
            var indexBuffer = new IndexBuffer(GraphicsDeviceHolder.Device, mesh.SumIndicesCount * sizeof(short),
                                              BufferUsage.WriteOnly, IndexElementSize.SixteenBits);

            meshParts3d = new List <ModelMeshPart3D>();
            int offset = 0;

            foreach (ModelMeshPartData part in mesh.MeshParts)
            {
                indexBuffer.SetData(offset * sizeof(short), part.Indices.ToArray(), 0, part.Indices.Count);
                meshParts3d.Add(new ModelMeshPart3D(offset, mesh.TriangleStrip ? part.Indices.Count - 2 : part.Indices.Count / 3, part.MaterialId));
                offset += part.Indices.Count;
            }

            if (offset != mesh.SumIndicesCount)
            {
                Utils.TerminateWithError("Incorrect total indices amount!");
            }

            return(indexBuffer);
        }
        private void ReadVertices(ModelMeshData mesh, int verticesCount)
        {
            mesh.Vertices = new List<Vector3>(verticesCount);

             for (var i = 0; i != verticesCount; ++i)
             {
            var x = input.ReadSingle();
            var y = input.ReadSingle(); // y and z coords are exchanged because of different coordinate system
            var z = input.ReadSingle();
            mesh.Vertices.Add(new Vector3(x, z, -y));
             }
        }
        private void ReadTriangles(ModelMeshData mesh, int trianglesCount)
        {
            ModelMeshPartData meshPart = new ModelMeshPartData(trianglesCount * 3, 0);
             mesh.SumIndicesCount = trianglesCount * 3;

             for (var i = 0; i != trianglesCount; ++i)
             {
            meshPart.Indices.Add(input.ReadInt16());
            meshPart.Indices.Add(input.ReadInt16());
            input.BaseStream.Seek(sizeof(short), SeekOrigin.Current); // skip index flags
            meshPart.Indices.Add(input.ReadInt16());
             }

             mesh.MeshParts = new List<ModelMeshPartData>();
             mesh.MeshParts.Add(meshPart);
        }
        private void ReadTextureCoords(ModelMeshData mesh, int verticesCount)
        {
            mesh.TextureCoords = new List<Vector2>(verticesCount);
             for (var i = 0; i != verticesCount; ++i)
             {
            float x = input.ReadSingle();
            float y = input.ReadSingle();

            mesh.TextureCoords.Add(new Vector2(x, y));
             }
        }
 private void ReadColors(ModelMeshData mesh, int verticesCount)
 {
     mesh.Colors = new List<Color>(verticesCount);
      for (int i = 0; i != verticesCount; ++i)
      {
     byte r = input.ReadByte();
     byte g = input.ReadByte();
     byte b = input.ReadByte();
     byte a = input.ReadByte();
     mesh.Colors.Add(new Color(r, g, b, a));
      }
 }
        /// <summary>
        /// Обрабатывает секцию Geometry
        /// Считывает вершины, треугольники (индексы вершин), нормали, текстурные координаты.
        /// </summary>
        private void ParseGeometry(DffVersion version)
        {
            ModelMeshData mesh = new ModelMeshData();

             GeometrySectionFlags flags = (GeometrySectionFlags)input.ReadInt16();

             input.BaseStream.Seek(sizeof(short), SeekOrigin.Current); // unknown

             int trianglesCount = input.ReadInt32();
             int verticesCount = input.ReadInt32();
             input.BaseStream.Seek(sizeof(int), SeekOrigin.Current); // morphTargetCount aka frameCount

             if (version < DffVersion.GTA_VC_2)
             {
            // geometry has lighting data. Ignoring it.
            // TODO :: we can use it for rendering!!!
            input.BaseStream.Seek(12, SeekOrigin.Current);
             }

             if ((flags & GeometrySectionFlags.MultipleTextureCoords) != GeometrySectionFlags.None)
            Log.Instance.Print("Multiple TexCoords sets are provided but used only the first of it!", MessageType.Warning);

             if ((flags & GeometrySectionFlags.HasColorInfo) != GeometrySectionFlags.None)
            ReadColors(mesh, verticesCount);
             else
            FillColors(mesh, verticesCount);

             if ((flags & GeometrySectionFlags.HasTextureCoords) != GeometrySectionFlags.None)
            ReadTextureCoords(mesh, verticesCount);

             ReadTriangles(mesh, trianglesCount);

             input.BaseStream.Seek(4 * sizeof(float), SeekOrigin.Current); // ignoring bounding sphere (x, y, z, radius)
             input.BaseStream.Seek(2 * sizeof(int), SeekOrigin.Current); // hasPosition, hasNormal (not used)

             ReadVertices(mesh, verticesCount);

             if ((flags & GeometrySectionFlags.HasNormalsInfo) != GeometrySectionFlags.None)
            ReadNormals(mesh, verticesCount);

             modelData.Meshes.Add(mesh);
        }
 private void FillColors(ModelMeshData mesh, int verticesCount)
 {
     mesh.Colors = new List<Color>(verticesCount);
      for (int i = 0; i != verticesCount; ++i)
     mesh.Colors.Add(new Color(0, 0, 0, 1));
 }