/// <summary>
        ///
        /// Meshes
        ///
        /// Parse mesh data
        /// Function decides if we are updating an already existing mesh or creating a new one.
        /// If a new mesh has been created this function will go through stored mesh instances
        /// and check if it can create new mesh instances.
        /// </summary>
        public static void ParseMeshData(System.IntPtr meshDataPtr)
        {
            try
            {
                var meshData = (MeshData)System.Runtime.InteropServices.Marshal.PtrToStructure(meshDataPtr, typeof(MeshData));

                // Convert unmanaged to managed memory
                ManagedMeshData managedMeshData = MeshHandler.ManageMeshMemory(meshData);

                // If all dependants are here, create or update the mesh
                bool dependencySuccess = MeshHandler.DependencyCheck(managedMeshData, meshData.entityToken);
                if (dependencySuccess)
                {
                    ParseMeshData(meshData, managedMeshData);

                    // Delete the data
                    ImportMenu.stpUnityDeleteMeshData(meshDataPtr);
                }
                else
                {
                    // If we are not able to create or update store the mesh data and try later
                    meshDataStore.Add(meshDataPtr);
                }
            }
            catch (System.Exception e)
            {
                Debug.LogException(e);

                // Delete the data
                ImportMenu.stpUnityDeleteMeshData(meshDataPtr);
            }
        }
        /// <summary>
        /// Create mesh
        /// Function that goes through the process of creating new mesh items.
        /// </summary>
        public static bool CreateMesh(MeshData meshData, ManagedMeshData managedMeshData)
        {
            Debug.LogFormat("Mesh - Token:{0}, Parent:{1}, {2} positions, {3} facesets", meshData.entityToken, meshData.entityParentToken, meshData.positionsNum, meshData.facesetsNum);

            // Get the index format of the mesh
            UnityEngine.Rendering.IndexFormat indexFormat;
            int maxVertexLimitSplit;

            GetIndexBufferConfiguration(
                managedMeshData.positions.Length,
                out indexFormat,
                out maxVertexLimitSplit);

            // Check if we need to split the mesh
            if (maxVertexLimitSplit == 0)
            {
                // Create simple mesh asset, create it's prefab object
                // and add it to the package mapper
                Mesh newMesh = new Mesh();
                UpdateMeshData(
                    managedMeshData.positions,
                    managedMeshData.normals,
                    managedMeshData.uvs,
                    managedMeshData.facesetNum,
                    managedMeshData.indices,
                    indexFormat,
                    ref newMesh
                    );

                CreateSimpleMeshAsset(
                    meshData.entityToken,
                    meshData.entityParentToken,
                    meshData.displayName,
                    managedMeshData.facesetNum,
                    managedMeshData.materials,
                    newMesh);
            }
            else
            {
                // Create split mesh assets, create hierarchy of prefabs
                // and add the root prefab to the package mapper
                List <Mesh> meshList = CreateSplitMeshes(
                    meshData.entityToken,
                    meshData.displayName,
                    managedMeshData
                    );

                CreateSplitMeshAsset(
                    meshData.entityToken,
                    meshData.displayName,
                    meshData.entityParentToken,
                    managedMeshData.facesetNum,
                    managedMeshData.materials,
                    meshList);
            }

            return(true);
        }
        /// <summary>
        /// Dependency check
        /// Checks if all of the dependencies of the mesh are available in Unity
        /// </summary>
        public static bool DependencyCheck(ManagedMeshData meshData, string entityToken)
        {
            // Check if we have materials available
            for (var i = 0; i < meshData.facesetNum; ++i)
            {
                if (!System.String.IsNullOrEmpty(meshData.materials[i]))
                {
                    // Check if we have a material instance or material definition ready for this mesh
                    if (!PackageMapper.GetMaterialFromToken(meshData.materials[i]))
                    {
                        // TODO: messages slow down the recieve mechanism and spam the log
                        //Debug.LogWarningFormat("Material '{0}' for '{1}' has not yet been created!",
                        //                         meshData.materials[i],
                        //                         entityToken);

                        return(false);
                    }
                }
            }

            return(true);
        }
        // Iterate through mesh store that were missing dependants and check if we can create new mesh objects
        // or update existing mesh objects
        public static void IterateMeshStore()
        {
            for (int i = meshDataStore.Count - 1; i >= 0; i--)
            {
                MeshData meshData = (MeshData)System.Runtime.InteropServices.Marshal.PtrToStructure(meshDataStore[i], typeof(MeshData));

                // Convert unmanaged to managed memory
                ManagedMeshData managedMeshData = MeshHandler.ManageMeshMemory(meshData);

                // If all dependants are here, create or update the mesh
                if (MeshHandler.DependencyCheck(managedMeshData, meshData.entityToken))
                {
                    ParseMeshData(meshData, managedMeshData);

                    // Delete the data
                    ImportMenu.stpUnityDeleteMeshData(meshDataStore[i]);

                    // Remove from the store
                    meshDataStore.RemoveAt(i);
                }
            }
        }
        /// <summary>
        /// Manage mesh memory
        /// Converts the marshaled unmanaged mesh memory to managed
        /// </summary>
        public static ManagedMeshData ManageMeshMemory(MeshData meshData)
        {
            ManagedMeshData managedMeshData = new ManagedMeshData();

            managedMeshData.positions = MarshallPositions((int)meshData.positionsNum, meshData.positions);
            managedMeshData.normals   = ((int)meshData.normalsNum > 0) ? MarshallNormals((int)meshData.normalsNum, meshData.normals) : null;

            managedMeshData.materials = new StringCollection();
            managedMeshData.indices   = new List <int[]>();
            var facesetdataSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(FacesetData));

            var currentReadPtr = meshData.facesets;

            for (var i = 0; i < (int)meshData.facesetsNum; ++i)
            {
                FacesetData fs = (FacesetData)System.Runtime.InteropServices.Marshal.PtrToStructure(currentReadPtr, typeof(FacesetData));
                managedMeshData.materials.Add(fs.materialName);
                managedMeshData.indices.Add(MarshallTriangleIndices((int)fs.indicesNum, fs.indices));
                currentReadPtr = MarshalData.AddToIntPtr(currentReadPtr, facesetdataSize);
            }
            managedMeshData.facesetNum = (int)meshData.facesetsNum;

            managedMeshData.uvs = new List <List <Vector2> >();
            currentReadPtr      = meshData.uvSets;
            var uvSetDataSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(UVData));

            for (var i = 0; i < (int)meshData.uvSetNum; ++i)
            {
                UVData uvData = (UVData)System.Runtime.InteropServices.Marshal.PtrToStructure(currentReadPtr, typeof(UVData));
                // Note: Not currently using triangle indices
                //managedMeshData.indices.Add(MarshallTriangleIndices((int)uvData.indicesNum, uvData.indices));
                managedMeshData.uvs.Add(MarshallUVData((int)uvData.uvsNum, uvData.uvs));
                currentReadPtr = MarshalData.AddToIntPtr(currentReadPtr, uvSetDataSize);
            }
            managedMeshData.uvNum = (int)meshData.uvSetNum;

            return(managedMeshData);
        }
        private static void ParseMeshData(MeshData meshData, ManagedMeshData managedMeshData)
        {
            // Check if the mesh already exists in the package mapper
            if (PackageMapper.TokenExistsInCache(meshData.entityToken))
            {
                // If mesh exists try to update it
                MeshHandler.UpdateMesh(meshData, managedMeshData);
            }
            else
            {
                // Create a new mesh object in Unity
                MeshHandler.CreateMesh(meshData, managedMeshData);

                // This loop starts over if we created a parent and a child is waiting in the store
                bool newItemCreated = true;
                while (newItemCreated)
                {
                    // Iterate through mesh instance store and try to create or update
                    // mesh instances that this mesh is a dependent of
                    IterateMeshInstanceStore(out newItemCreated);
                }
            }
        }
        UpdateSimpleMeshAsset(
            string entityToken,
            string displayName,
            ManagedMeshData managedMeshData,
            Mesh mesh,
            GameObject meshPrefab)
        {
            // Update the mesh renderer
            Material[] materials = GetMeshMaterials(managedMeshData.facesetNum, managedMeshData.materials, entityToken);

            var meshRenderer = meshPrefab.GetComponent <MeshRenderer>();

            if (meshRenderer)
            {
                meshRenderer.materials = materials;
            }

            // Update mesh name
            mesh.name = displayName;

            AssetDatabase.SaveAssets();

            return(true);
        }
        CreateSplitMeshes(
            string entityToken,
            string displayName,
            ManagedMeshData managedMeshData)
        {
            List <Mesh> meshList = new List <Mesh>();

            int max_vertex_limit_split;

            UnityEngine.Rendering.IndexFormat indexFormat;
            GetIndexBufferConfiguration(
                managedMeshData.positions.Length,
                out indexFormat,
                out max_vertex_limit_split);

            // now split the geometry into N meshes, as children of this new game object, and the identity transform
            var current_offset     = 0;
            var remaining_vertices = managedMeshData.positions.Length;
            var split_index        = 0;

            while (remaining_vertices > 0)
            {
                var segment_size    = System.Math.Min(remaining_vertices, max_vertex_limit_split);
                var positionSegment = CopyArraySegment(managedMeshData.positions, current_offset, segment_size);
                var normalSegment   = CopyArraySegment(managedMeshData.normals, current_offset, segment_size);

                if (positionSegment == null || normalSegment == null)
                {
                    throw new System.Exception(System.String.Format("Unindexed mesh creation failure! Token:{0} Name:{1} Part:{2}", entityToken, displayName, System.String.Format("Split_{0}", split_index)));
                }

                var indicesSegment = new List <int[]>();
                for (var i = 0; i < managedMeshData.indices.Count; ++i)
                {
                    var segment = CopyArraySegmentAndRebase(managedMeshData.indices[i], current_offset, segment_size);
                    if (segment == null)
                    {
                        throw new System.Exception(System.String.Format("Unindexed mesh creation failure! Token:{0} Name:{1} Part:{2}", entityToken, displayName, System.String.Format("Split_{0}", split_index)));
                    }

                    indicesSegment.Add(segment);
                }

                var uvSegment = new List <List <Vector2> >();
                for (var i = 0; i < managedMeshData.uvNum; ++i)
                {
                    uvSegment.Add(CopyListSegment(managedMeshData.uvs[i], current_offset, segment_size));
                }

                Mesh mesh = new Mesh();
                UpdateMeshData(
                    positionSegment,
                    normalSegment,
                    uvSegment,
                    managedMeshData.facesetNum,
                    indicesSegment,
                    indexFormat,
                    ref mesh);

                if (!mesh)
                {
                    throw new System.Exception(System.String.Format("Unindexed mesh creation failure! Token:{0} Name:{1} Part:{2}", entityToken, displayName, System.String.Format("Split_{0}", split_index)));
                }

                meshList.Add(mesh);

                current_offset     += segment_size;
                remaining_vertices -= segment_size;
                ++split_index;
            }

            return(meshList);
        }
        /// <summary>
        /// Update mesh
        /// Function that goes through the process of updating existing mesh item.
        /// Checking for unindexed or indexed meshes.
        /// </summary>
        public static bool UpdateMesh(MeshData meshData, ManagedMeshData managedMeshData)
        {
            Debug.LogFormat("Mesh Update - Token:{0}, Parent:{1}, {2} positions, {3} facesets", meshData.entityToken, meshData.entityParentToken, meshData.positionsNum, meshData.facesetsNum);

            // Find existing mesh
            Mesh mesh = PackageMapper.GetMeshFromToken(meshData.entityToken);

            if (!mesh)
            {
                return(false);
            }

            // Get the index format of the mesh
            UnityEngine.Rendering.IndexFormat indexFormat;
            int maxVertexLimitSplit;

            GetIndexBufferConfiguration(
                managedMeshData.positions.Length,
                out indexFormat,
                out maxVertexLimitSplit);

            // Get the prefab object
            GameObject prefab = PackageMapper.GetObjectFromToken(meshData.entityToken) as GameObject;

            // Check if we need to split the mesh
            if (maxVertexLimitSplit == 0)
            {
                // Update existing mesh
                UpdateMeshData(
                    managedMeshData.positions,
                    managedMeshData.normals,
                    managedMeshData.uvs,
                    managedMeshData.facesetNum,
                    managedMeshData.indices,
                    indexFormat,
                    ref mesh
                    );

                UpdateSimpleMeshAsset(
                    meshData.entityToken,
                    meshData.displayName,
                    managedMeshData,
                    mesh,
                    prefab
                    );
            }
            else
            {
                // Delete prefab first
                AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(prefab));

                // Create split mesh assets, create hierarchy of prefabs
                // and add the root prefab to the package mapper
                List <Mesh> meshList = CreateSplitMeshes(
                    meshData.entityToken,
                    meshData.displayName,
                    managedMeshData
                    );

                CreateSplitMeshAsset(
                    meshData.entityToken,
                    meshData.displayName,
                    meshData.entityParentToken,
                    managedMeshData.facesetNum,
                    managedMeshData.materials,
                    meshList);
            }

            mesh.UploadMeshData(false);

            return(true);
        }