static void CalculateBounds(MeshImportJob jobData)
        {
            var upperBound = new Vector3(float.MinValue, float.MinValue, float.MinValue);
            var lowerBound = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);

            var count = jobData.Vertices.Length;

            for (var i = 0; i < count; ++i)
            {
                var vertex = jobData.Vertices[i];

                if (vertex.Position.x > upperBound.x)
                {
                    upperBound.x = vertex.Position.x;
                }
                if (vertex.Position.y > upperBound.y)
                {
                    upperBound.y = vertex.Position.y;
                }
                if (vertex.Position.z > upperBound.z)
                {
                    upperBound.z = vertex.Position.z;
                }

                if (vertex.Position.x < lowerBound.x)
                {
                    lowerBound.x = vertex.Position.x;
                }
                if (vertex.Position.y < lowerBound.y)
                {
                    lowerBound.y = vertex.Position.y;
                }
                if (vertex.Position.z < lowerBound.z)
                {
                    lowerBound.z = vertex.Position.z;
                }
            }

            jobData.MeshBounds = new Bounds((lowerBound + upperBound) * 0.5f, upperBound - lowerBound);
        }
        static MeshImportJob ImportMesh <T>(SyncMesh syncMesh)
            where T : struct
        {
            var data = new MeshImportJob {
                SyncMesh = syncMesh
            };
            var toggle = new IndexToggle <T>(data);

            var count = syncMesh.Vertices.Count;

            data.Vertices = new Vertex[count];

            for (var i = 0; i < count; ++i)
            {
                var v = syncMesh.Vertices[i];
                data.Vertices[i].Position = new Vector3(v.X, v.Y, v.Z);
            }

            count = syncMesh.Normals.Count;
            for (var i = 0; i < count; ++i)
            {
                var n = syncMesh.Normals[i];
                data.Vertices[i].Normal = new Vector3(n.X, n.Y, n.Z);
            }

            count = syncMesh.Uvs.Count;
            for (var i = 0; i < count; ++i)
            {
                var u = syncMesh.Uvs[i];
                data.Vertices[i].UV = new Vector2(u.X, u.Y);
            }

            var subMeshCount = syncMesh.SubMeshes.Count;
            var nbIndices    = syncMesh.SubMeshes.Sum(x => x.Triangles.Count);

            toggle.InstantiateArray(nbIndices);

            data.SubMeshStarts  = new int[syncMesh.SubMeshes.Count];
            data.SubMeshLengths = new int[syncMesh.SubMeshes.Count];

            var offset = 0;

            for (var i = 0; i < subMeshCount; ++i)
            {
                count = syncMesh.SubMeshes[i].Triangles.Count;

                data.SubMeshStarts[i]  = offset;
                data.SubMeshLengths[i] = count;

                var index = 0;
                foreach (var triangleIndex in syncMesh.SubMeshes[i].Triangles)
                {
                    toggle.Set(offset + index++, triangleIndex);
                }

                offset += count;
            }

            CalculateBounds(data);
            CalculateMeshTangents(data, toggle);

            return(data);
        }
        static void CalculateMeshTangents <T>(MeshImportJob jobData, IndexToggle <T> toggle) where T : struct
        {
            // Todo: Validate that this function is yielding the same result as the internal unity function
            var vertices = jobData.Vertices;

            var triangleCount = toggle.GetLength();
            var vertexCount   = vertices.Length;

            var tan1 = new Vector3[vertexCount];
            var tan2 = new Vector3[vertexCount];

            for (long a = 0; a < triangleCount; a += 3)
            {
                long i1 = toggle.Get(a + 0);
                long i2 = toggle.Get(a + 1);
                long i3 = toggle.Get(a + 2);

                var v1 = vertices[i1].Position;
                var v2 = vertices[i2].Position;
                var v3 = vertices[i3].Position;

                var w1 = vertices[i1].UV;
                var w2 = vertices[i2].UV;
                var w3 = vertices[i3].UV;

                var x1 = v2.x - v1.x;
                var x2 = v3.x - v1.x;
                var y1 = v2.y - v1.y;
                var y2 = v3.y - v1.y;
                var z1 = v2.z - v1.z;
                var z2 = v3.z - v1.z;

                var s1 = w2.x - w1.x;
                var s2 = w3.x - w1.x;
                var t1 = w2.y - w1.y;
                var t2 = w3.y - w1.y;

                var div = s1 * t2 - s2 * t1;
                var r   = div == 0.0f ? 0.0f : 1.0f / (s1 * t2 - s2 * t1);

                var sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
                var tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);

                tan1[i1] += sdir;
                tan1[i2] += sdir;
                tan1[i3] += sdir;

                tan2[i1] += tdir;
                tan2[i2] += tdir;
                tan2[i3] += tdir;
            }

            for (long a = 0; a < vertexCount; ++a)
            {
                var n = vertices[a].Normal;
                var t = tan1[a];

                Vector3.OrthoNormalize(ref n, ref t);
                vertices[a].Tangent.Set(t.x, t.y, t.z, Vector3.Dot(Vector3.Cross(n, t), tan2[a]) < 0.0f ? -1.0f : 1.0f);
            }
        }
 public IndexToggle(MeshImportJob jobData)
 {
     m_JobData = jobData;
 }