Beispiel #1
0
 public GeneratedMeshKey(GeneratedMeshDescription meshDescription)
 {
     geometryHashValue  = meshDescription.geometryHashValue;
     surfaceHashValue   = meshDescription.surfaceHashValue;
     vertexCount        = meshDescription.vertexCount;
     indexCount         = meshDescription.indexCount;
     usedVertexChannels = meshDescription.meshQuery.UsedVertexChannels;
 }
Beispiel #2
0
        public static int Calculate(GeneratedMeshDescription meshDescription)
        {
            var hashCode = -190551774;

            hashCode = hashCode * -1521134295 + (int)meshDescription.meshQuery.UsedVertexChannels;
            hashCode = hashCode * -1521134295 + (int)meshDescription.geometryHashValue;
            hashCode = hashCode * -1521134295 + (int)meshDescription.surfaceHashValue;
            hashCode = hashCode * -1521134295 + (int)meshDescription.vertexCount;
            hashCode = hashCode * -1521134295 + (int)meshDescription.indexCount;
            return(hashCode);
        }
Beispiel #3
0
        private static GeneratedMeshDescription[] GetMeshDescriptions(Int32 treeNodeID,
                                                                      MeshQuery[]                meshQueries,
                                                                      VertexChannelFlags vertexChannelMask)
        {
            if (meshQueries == null)
            {
                throw new ArgumentNullException("meshTypes");
            }

            if (meshQueries.Length == 0)
            {
                return(null);
            }

            Int32 meshDescriptionCount;

            var nativeMeshTypeHandle = GCHandle.Alloc(meshQueries, GCHandleType.Pinned);
            var nativeMeshTypePtr    = nativeMeshTypeHandle.AddrOfPinnedObject();

            var result = GenerateMeshDescriptions(treeNodeID, meshQueries.Length, nativeMeshTypePtr, vertexChannelMask, out meshDescriptionCount);

            nativeMeshTypeHandle.Free();
            if (!result || meshDescriptionCount == 0)
            {
                return(null);
            }

            var meshDescriptions       = new GeneratedMeshDescription[meshDescriptionCount];
            var meshDescriptionsHandle = GCHandle.Alloc(meshDescriptions, GCHandleType.Pinned);
            var meshDescriptionsPtr    = meshDescriptionsHandle.AddrOfPinnedObject();

            result = GetMeshDescriptions(treeNodeID, meshDescriptionCount, meshDescriptionsPtr);

            meshDescriptionsHandle.Free();

            if (!result ||
                meshDescriptions[0].vertexCount <= 0 ||
                meshDescriptions[0].indexCount <= 0)
            {
                return(null);
            }

            return(meshDescriptions);
        }
 /// <summary>Creates and returns a <see cref="Chisel.Core.GeneratedMeshContents"/> for a given <see cref="Chisel.Core.GeneratedMeshDescription"/> created by <see cref="Chisel.Core.CSGTree.GetMeshDescriptions"/></summary>
 /// <remarks>See the [Create Unity Meshes](~/documentation/createUnityMesh.md) article for more information.</remarks>
 /// <param name="meshDescription">A <see cref="Chisel.Core.GeneratedMeshDescription"/> created by <see cref="Chisel.Core.CSGTree.GetMeshDescriptions"/>.</param>
 /// <param name="previousGeneratedMeshContents">The previously generated <see cref="Chisel.Core.GeneratedMeshContents"/>, this can reuse allocated memory if the mesh hasn't changed shape. (optional)</param>
 /// <returns>A <see cref="Chisel.Core.GeneratedMeshContents"/> that can be used to initialize a [UnityEngine.Mesh](https://docs.unity3d.com/ScriptReference/Mesh.html) with.</returns>
 /// <seealso cref="Chisel.Core.CSGTree.GetMeshDescriptions"/>
 public GeneratedMeshContents            GetGeneratedMesh(GeneratedMeshDescription meshDescription, GeneratedMeshContents previousGeneratedMeshContents = null)
 {
     return(GetGeneratedMesh(treeNodeID, meshDescription, previousGeneratedMeshContents));
 }
Beispiel #5
0
        internal static GeneratedMeshDescription[] GetMeshDescriptions(Int32 treeNodeID,
                                                                       MeshQuery[]          meshQueries,
                                                                       VertexChannelFlags vertexChannelMask)
        {
            if (!AssertNodeIDValid(treeNodeID) || !AssertNodeType(treeNodeID, CSGNodeType.Tree))
            {
                return(null);
            }
            if (meshQueries == null)
            {
                throw new ArgumentNullException("meshTypes");
            }

            if (meshQueries.Length == 0)
            {
                Debug.Log("meshQueries.Length == 0");
                return(null);
            }

            if (!IsValidNodeID(treeNodeID))
            {
                Debug.LogError("GenerateMeshDescriptions: Invalid node index used");
                return(null);
            }

            var treeNodeIndex = treeNodeID - 1;
            var treeInfo      = nodeHierarchies[treeNodeIndex].treeInfo;

            if (treeInfo == null)
            {
                Debug.LogError("GenerateMeshDescriptions: Invalid node index used");
                return(null);
            }

            treeInfo.subMeshCounts.Clear();
            treeInfo.meshDescriptions.Clear();

            if (nodeFlags[treeNodeIndex].IsNodeFlagSet(NodeStatusFlags.TreeNeedsUpdate))
            {
                UnityEngine.Profiling.Profiler.BeginSample("UpdateTreeMesh");
                try
                {
                    var handle = UpdateTreeMeshes(new int[] { treeNodeID });
                    handle.Complete();
                } finally { UnityEngine.Profiling.Profiler.EndSample(); }
            }

            UnityEngine.Profiling.Profiler.BeginSample("CombineSubMeshes");
            try
            {
                CombineSubMeshes(treeInfo, meshQueries, vertexChannelMask);
            } finally { UnityEngine.Profiling.Profiler.EndSample(); }


            {
                var flags = nodeFlags[treeNodeIndex];
                flags.UnSetNodeFlag(NodeStatusFlags.TreeMeshNeedsUpdate);
                nodeFlags[treeNodeIndex] = flags;
            }

            if (treeInfo.subMeshCounts.Count <= 0)
            {
                return(null);
            }

            for (int i = (int)treeInfo.subMeshCounts.Count - 1; i >= 0; i--)
            {
                var subMesh = treeInfo.subMeshCounts[i];

                // Make sure the meshDescription actually holds a mesh
                if (subMesh.vertexCount == 0 ||
                    subMesh.indexCount == 0)
                {
                    continue;
                }

                // Make sure the mesh is valid
                if (subMesh.vertexCount >= kMaxVertexCount)
                {
                    Debug.LogError("Mesh has too many vertices (" + subMesh.vertexCount + " > " + kMaxVertexCount + ")");
                    continue;
                }

                var description = new GeneratedMeshDescription
                {
                    meshQuery         = subMesh.meshQuery,
                    surfaceParameter  = subMesh.surfaceIdentifier,
                    meshQueryIndex    = subMesh.meshIndex,
                    subMeshQueryIndex = subMesh.subMeshIndex,

                    geometryHashValue = subMesh.geometryHash,
                    surfaceHashValue  = subMesh.surfaceHash,

                    vertexCount = subMesh.vertexCount,
                    indexCount  = subMesh.indexCount
                };

                treeInfo.meshDescriptions.Add(description);
            }

            if (treeInfo.meshDescriptions == null ||
                treeInfo.meshDescriptions.Count == 0 ||
                treeInfo.meshDescriptions[0].vertexCount <= 0 ||
                treeInfo.meshDescriptions[0].indexCount <= 0)
            {
                return(null);
            }

            return(treeInfo.meshDescriptions.ToArray());
        }
Beispiel #6
0
        internal static GeneratedMeshContents GetGeneratedMesh(int treeNodeID, GeneratedMeshDescription meshDescription)
        {
            if (!AssertNodeIDValid(treeNodeID) || !AssertNodeType(treeNodeID, CSGNodeType.Tree))
            {
                return(null);
            }
            if (meshDescription.vertexCount <= 3 ||
                meshDescription.indexCount <= 3)
            {
                Debug.LogWarning(string.Format("{0} called with a {1} that isn't valid", typeof(CSGTree).Name, typeof(GeneratedMeshDescription).Name));
                return(null);
            }

            var meshIndex    = meshDescription.meshQueryIndex;
            var subMeshIndex = meshDescription.subMeshQueryIndex;

            if (meshIndex < 0)
            {
                Debug.LogError("GetGeneratedMesh: MeshIndex cannot be negative"); return(null);
            }
            if (subMeshIndex < 0)
            {
                Debug.LogError("GetGeneratedMesh: SubMeshIndex cannot be negative"); return(null);
            }

            if (nodeHierarchies[treeNodeID - 1].treeInfo == null)
            {
                Debug.LogWarning("Tree has not been initialized properly"); return(null);
            }

            TreeInfo tree = nodeHierarchies[treeNodeID - 1].treeInfo;

            if (tree == null)
            {
                Debug.LogError("GetGeneratedMesh: Invalid node index used"); return(null);
            }
            if (tree.subMeshCounts == null)
            {
                Debug.LogWarning("Tree has not been initialized properly"); return(null);
            }



            int subMeshCountSize = (int)tree.subMeshCounts.Count;

            if (subMeshIndex >= (int)subMeshCountSize)
            {
                Debug.LogError("GetGeneratedMesh: SubMeshIndex is higher than the number of generated meshes"); return(null);
            }
            if (meshIndex >= (int)subMeshCountSize)
            {
                Debug.LogError("GetGeneratedMesh: MeshIndex is higher than the number of generated meshes"); return(null);
            }

            int foundIndex = -1;

            for (int i = 0; i < subMeshCountSize; i++)
            {
                if (meshIndex == tree.subMeshCounts[i].meshIndex &&
                    subMeshIndex == tree.subMeshCounts[i].subMeshIndex)
                {
                    foundIndex = i;
                    break;
                }
            }
            if (foundIndex < 0 || foundIndex >= subMeshCountSize)
            {
                Debug.LogError("GetGeneratedMesh: Could not find mesh associated with MeshIndex/SubMeshIndex pair"); return(null);
            }

            var subMeshCount = tree.subMeshCounts[foundIndex];

            if (subMeshCount.indexCount > meshDescription.indexCount)
            {
                Debug.LogError("GetGeneratedMesh: The destination indices array (" + meshDescription.indexCount + ") is smaller than the size of the source data (" + (int)subMeshCount.indexCount + ")"); return(null);
            }
            if (subMeshCount.vertexCount > meshDescription.vertexCount)
            {
                Debug.LogError("GetGeneratedMesh: The destination vertices array (" + meshDescription.vertexCount + ") is smaller than the size of the source data (" + (int)subMeshCount.vertexCount + ")"); return(null);
            }
            if (subMeshCount.indexCount == 0 || subMeshCount.vertexCount == 0)
            {
                Debug.LogWarning("GetGeneratedMesh: Mesh is empty"); return(null);
            }


            var generatedMesh      = new GeneratedMeshContents();
            var usedVertexChannels = meshDescription.meshQuery.UsedVertexChannels;
            var vertexCount        = meshDescription.vertexCount;
            var indexCount         = meshDescription.indexCount;

            generatedMesh.description = meshDescription;

            // create our arrays on the managed side with the correct size

            bool useTangents = ((usedVertexChannels & VertexChannelFlags.Tangent) == VertexChannelFlags.Tangent);
            bool useNormals  = ((usedVertexChannels & VertexChannelFlags.Normal) == VertexChannelFlags.Normal);
            bool useUV0      = ((usedVertexChannels & VertexChannelFlags.UV0) == VertexChannelFlags.UV0);

            generatedMesh.tangents     = useTangents ? new NativeArray <float4>(vertexCount, Allocator.Persistent) : default;
            generatedMesh.normals      = useNormals  ? new NativeArray <float3>(vertexCount, Allocator.Persistent) : default;
            generatedMesh.uv0          = useUV0      ? new NativeArray <float2>(vertexCount, Allocator.Persistent) : default;
            generatedMesh.positions    = new NativeArray <float3>(vertexCount, Allocator.Persistent);
            generatedMesh.indices      = new NativeArray <int>   (indexCount, Allocator.Persistent);
            generatedMesh.brushIndices = new NativeArray <int>   (indexCount / 3, Allocator.Persistent);

            generatedMesh.bounds = new Bounds();

            var submeshVertexCount = subMeshCount.vertexCount;
            var submeshIndexCount  = subMeshCount.indexCount;

            if (subMeshCount.surfaces == null ||
                submeshVertexCount != generatedMesh.positions.Length ||
                submeshIndexCount != generatedMesh.indices.Length ||
                generatedMesh.indices == null ||
                generatedMesh.positions == null)
            {
                return(null);
            }


            var submeshSurfaces = new NativeArray <SubMeshSurface>(subMeshCount.surfaces.Count, Allocator.TempJob);

            for (int n = 0; n < subMeshCount.surfaces.Count; n++)
            {
                submeshSurfaces[n] = subMeshCount.surfaces[n];
            }

            var generateVertexBuffersJob = new GenerateVertexBuffersJob
            {
                meshQuery         = subMeshCount.meshQuery,
                surfaceIdentifier = subMeshCount.surfaceIdentifier,

                submeshIndexCount  = subMeshCount.indexCount,
                submeshVertexCount = subMeshCount.vertexCount,

                submeshSurfaces = submeshSurfaces,

                generatedMeshIndices      = generatedMesh.indices,
                generatedMeshBrushIndices = generatedMesh.brushIndices,
                generatedMeshPositions    = generatedMesh.positions,
                generatedMeshTangents     = generatedMesh.tangents,
                generatedMeshNormals      = generatedMesh.normals,
                generatedMeshUV0          = generatedMesh.uv0
            };

            generateVertexBuffersJob.Run();

            generateVertexBuffersJob.submeshSurfaces.Dispose();
            generateVertexBuffersJob.submeshSurfaces = default;

            var min = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
            var max = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);

            for (int i = 0, count = subMeshCount.indexCount; i < count; i++)
            {
                var position = generatedMesh.positions[generatedMesh.indices[i]];
                min.x = Mathf.Min(min.x, position.x);
                min.y = Mathf.Min(min.y, position.y);
                min.z = Mathf.Min(min.z, position.z);

                max.x = Mathf.Max(max.x, position.x);
                max.y = Mathf.Max(max.y, position.y);
                max.z = Mathf.Max(max.z, position.z);
            }

            var boundsCenter = (max + min) * 0.5f;
            var boundsSize   = (max - min);

            if (float.IsInfinity(boundsSize.x) || float.IsInfinity(boundsSize.y) || float.IsInfinity(boundsSize.z) ||
                float.IsNaN(boundsSize.x) || float.IsNaN(boundsSize.y) || float.IsNaN(boundsSize.z))
            {
                return(null);
            }

            generatedMesh.bounds = new Bounds(boundsCenter, boundsSize);
            return(generatedMesh);
        }
Beispiel #7
0
 private static GeneratedMeshContents GetGeneratedMesh(int treeNodeID, GeneratedMeshDescription meshDescription, GeneratedMeshContents previousGeneratedMeshContents)
 {
     return(CSGManager.GetGeneratedMesh(treeNodeID, meshDescription, previousGeneratedMeshContents));
 }
Beispiel #8
0
 /// <summary>Creates and returns a <see cref="Chisel.Core.GeneratedMeshContents"/> for a given <see cref="Chisel.Core.GeneratedMeshDescription"/> created by <see cref="Chisel.Core.CSGTree.GetMeshDescriptions"/></summary>
 /// <remarks>See the [Create Unity Meshes](~/documentation/createUnityMesh.md) article for more information.</remarks>
 /// <param name="meshDescription">A <see cref="Chisel.Core.GeneratedMeshDescription"/> created by <see cref="Chisel.Core.CSGTree.GetMeshDescriptions"/>.</param>
 /// <param name="previousGeneratedMeshContents">The previously generated <see cref="Chisel.Core.GeneratedMeshContents"/>, this can reuse allocated memory if the mesh hasn't changed shape. (optional)</param>
 /// <returns>A <see cref="Chisel.Core.GeneratedMeshContents"/> that can be used to initialize a [UnityEngine.Mesh](https://docs.unity3d.com/ScriptReference/Mesh.html) with.</returns>
 /// <seealso cref="Chisel.Core.CSGTree.GetMeshDescriptions"/>
 public GeneratedMeshContents            GetGeneratedMesh(GeneratedMeshDescription meshDescription)
 {
     return(GetGeneratedMesh(treeNodeID, meshDescription));
 }
Beispiel #9
0
        internal static GeneratedMeshContents GetGeneratedMesh(int treeNodeID, GeneratedMeshDescription meshDescription, GeneratedMeshContents previousGeneratedMeshContents)
        {
            if (!AssertNodeIDValid(treeNodeID) || !AssertNodeType(treeNodeID, CSGNodeType.Tree))
            {
                return(null);
            }
            if (meshDescription.vertexCount <= 0 ||
                meshDescription.indexCount <= 0)
            {
                Debug.LogWarning(string.Format("{0} called with a {1} that isn't valid", typeof(CSGTree).Name, typeof(GeneratedMeshDescription).Name));
                return(null);
            }

            var meshIndex    = meshDescription.meshQueryIndex;
            var subMeshIndex = meshDescription.subMeshQueryIndex;

            if (meshIndex < 0)
            {
                Debug.LogError("GetGeneratedMesh: MeshIndex cannot be negative"); return(null);
            }
            if (subMeshIndex < 0)
            {
                Debug.LogError("GetGeneratedMesh: SubMeshIndex cannot be negative"); return(null);
            }

            if (nodeHierarchies[treeNodeID - 1].treeInfo == null)
            {
                Debug.LogWarning("Tree has not been initialized properly"); return(null);
            }

            TreeInfo tree = nodeHierarchies[treeNodeID - 1].treeInfo;

            if (tree == null)
            {
                Debug.LogError("GetGeneratedMesh: Invalid node index used"); return(null);
            }
            if (tree.subMeshCounts == null)
            {
                Debug.LogWarning("Tree has not been initialized properly"); return(null);
            }



            int subMeshCountSize = (int)tree.subMeshCounts.Count;

            if (subMeshIndex >= (int)subMeshCountSize)
            {
                Debug.LogError("GetGeneratedMesh: SubMeshIndex is higher than the number of generated meshes"); return(null);
            }
            if (meshIndex >= (int)subMeshCountSize)
            {
                Debug.LogError("GetGeneratedMesh: MeshIndex is higher than the number of generated meshes"); return(null);
            }

            int foundIndex = -1;

            for (int i = 0; i < subMeshCountSize; i++)
            {
                if (meshIndex == tree.subMeshCounts[i].meshIndex &&
                    subMeshIndex == tree.subMeshCounts[i].subMeshIndex)
                {
                    foundIndex = i;
                    break;
                }
            }
            if (foundIndex < 0 || foundIndex >= subMeshCountSize)
            {
                Debug.LogError("GetGeneratedMesh: Could not find mesh associated with MeshIndex/SubMeshIndex pair"); return(null);
            }

            var subMeshCount = tree.subMeshCounts[foundIndex];

            if (subMeshCount.indexCount > meshDescription.indexCount)
            {
                Debug.LogError("GetGeneratedMesh: The destination indices array (" + meshDescription.indexCount + ") is smaller than the size of the source data (" + (int)subMeshCount.indexCount + ")"); return(null);
            }
            if (subMeshCount.vertexCount > meshDescription.vertexCount)
            {
                Debug.LogError("GetGeneratedMesh: The destination vertices array (" + meshDescription.vertexCount + ") is smaller than the size of the source data (" + (int)subMeshCount.vertexCount + ")"); return(null);
            }
            if (subMeshCount.indexCount == 0 || subMeshCount.vertexCount == 0)
            {
                Debug.LogWarning("GetGeneratedMesh: Mesh is empty"); return(null);
            }



            var generatedMesh      = (previousGeneratedMeshContents != null) ? previousGeneratedMeshContents : new GeneratedMeshContents();
            var usedVertexChannels = meshDescription.meshQuery.UsedVertexChannels;
            var vertexCount        = meshDescription.vertexCount;
            var indexCount         = meshDescription.indexCount;

            generatedMesh.description = meshDescription;

            // create our arrays on the managed side with the correct size
            generatedMesh.tangents  = ((usedVertexChannels & VertexChannelFlags.Tangent) == 0) ? null : (generatedMesh.tangents != null && generatedMesh.tangents.Length == vertexCount) ? generatedMesh.tangents : new Vector4[vertexCount];
            generatedMesh.normals   = ((usedVertexChannels & VertexChannelFlags.Normal) == 0) ? null : (generatedMesh.normals != null && generatedMesh.normals.Length == vertexCount) ? generatedMesh.normals  : new Vector3[vertexCount];
            generatedMesh.uv0       = ((usedVertexChannels & VertexChannelFlags.UV0) == 0) ? null : (generatedMesh.uv0 != null && generatedMesh.uv0.Length == vertexCount) ? generatedMesh.uv0      : new Vector2[vertexCount];
            generatedMesh.positions = (generatedMesh.positions != null && generatedMesh.positions.Length == vertexCount) ? generatedMesh.positions : new Vector3[vertexCount];
            generatedMesh.indices   = (generatedMesh.indices != null && generatedMesh.indices.Length == indexCount) ? generatedMesh.indices   : new int    [indexCount];

            generatedMesh.bounds = new Bounds();


            bool result = CSGManager.GenerateVertexBuffers(subMeshCount, generatedMesh);

            if (!result)
            {
                return(null);
            }

            var min = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
            var max = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);

            for (int i = 0, count = subMeshCount.indexCount; i < count; i++)
            {
                var position = generatedMesh.positions[generatedMesh.indices[i]];
                min.x = Mathf.Min(min.x, position.x);
                min.y = Mathf.Min(min.y, position.y);
                min.z = Mathf.Min(min.z, position.z);

                max.x = Mathf.Max(max.x, position.x);
                max.y = Mathf.Max(max.y, position.y);
                max.z = Mathf.Max(max.z, position.z);
            }

            var boundsCenter = (max + min) * 0.5f;
            var boundsSize   = (max - min);

            if (float.IsInfinity(boundsSize.x) || float.IsInfinity(boundsSize.y) || float.IsInfinity(boundsSize.z) ||
                float.IsNaN(boundsSize.x) || float.IsNaN(boundsSize.y) || float.IsNaN(boundsSize.z))
            {
                return(null);
            }

            generatedMesh.bounds = new Bounds(boundsCenter, boundsSize);
            return(generatedMesh);
        }
Beispiel #10
0
        private static GeneratedMeshContents GetGeneratedMesh(int treeNodeID, GeneratedMeshDescription meshDescription, GeneratedMeshContents previousGeneratedMeshContents)
        {
            if (meshDescription.vertexCount <= 0 ||
                meshDescription.indexCount <= 0)
            {
                Debug.LogWarning(string.Format("{0} called with a {1} that isn't valid", typeof(CSGTree).Name, typeof(GeneratedMeshDescription).Name));
                return(null);
            }

            var generatedMesh      = (previousGeneratedMeshContents != null) ? previousGeneratedMeshContents : new GeneratedMeshContents();
            var usedVertexChannels = meshDescription.meshQuery.UsedVertexChannels;
            var vertexCount        = meshDescription.vertexCount;
            var indexCount         = meshDescription.indexCount;
            var meshIndex          = meshDescription.meshQueryIndex;
            var subMeshIndex       = meshDescription.subMeshQueryIndex;

            generatedMesh.description = meshDescription;

            // create our arrays on the managed side with the correct size
            generatedMesh.tangents  = ((usedVertexChannels & VertexChannelFlags.Tangent) == 0) ? null : (generatedMesh.tangents != null && generatedMesh.tangents.Length == vertexCount) ? generatedMesh.tangents : new Vector4[vertexCount];
            generatedMesh.normals   = ((usedVertexChannels & VertexChannelFlags.Normal) == 0) ? null : (generatedMesh.normals != null && generatedMesh.normals.Length == vertexCount) ? generatedMesh.normals  : new Vector3[vertexCount];
            generatedMesh.uv0       = ((usedVertexChannels & VertexChannelFlags.UV0) == 0) ? null : (generatedMesh.uv0 != null && generatedMesh.uv0.Length == vertexCount) ? generatedMesh.uv0      : new Vector2[vertexCount];
            generatedMesh.positions = (generatedMesh.positions != null && generatedMesh.positions.Length == vertexCount) ? generatedMesh.positions : new Vector3[vertexCount];
            generatedMesh.indices   = (generatedMesh.indices != null && generatedMesh.indices.Length == indexCount) ? generatedMesh.indices   : new int    [indexCount];

            var indicesHandle  = GCHandle.Alloc(generatedMesh.indices, GCHandleType.Pinned);
            var positionHandle = GCHandle.Alloc(generatedMesh.positions, GCHandleType.Pinned);
            var tangentHandle  = new GCHandle();
            var normalHandle   = new GCHandle();
            var uv0Handle      = new GCHandle();

            var indicesPtr  = indicesHandle.AddrOfPinnedObject();
            var positionPtr = positionHandle.AddrOfPinnedObject();
            var tangentPtr  = IntPtr.Zero;
            var normalPtr   = IntPtr.Zero;
            var uv0Ptr      = IntPtr.Zero;

            if (generatedMesh.tangents != null)
            {
                tangentHandle = GCHandle.Alloc(generatedMesh.tangents, GCHandleType.Pinned); tangentPtr = tangentHandle.AddrOfPinnedObject();
            }
            if (generatedMesh.normals != null)
            {
                normalHandle = GCHandle.Alloc(generatedMesh.normals, GCHandleType.Pinned); normalPtr = normalHandle.AddrOfPinnedObject();
            }
            if (generatedMesh.uv0 != null)
            {
                uv0Handle = GCHandle.Alloc(generatedMesh.uv0, GCHandleType.Pinned); uv0Ptr = uv0Handle.AddrOfPinnedObject();
            }

            var boundsCenter = Vector3.zero;
            var boundsSize   = Vector3.zero;
            var result       = GetGeneratedMesh((Int32)treeNodeID,
                                                (Int32)meshIndex,
                                                (Int32)subMeshIndex,

                                                (Int32)indexCount,
                                                indicesPtr,

                                                (Int32)vertexCount,
                                                positionPtr,
                                                tangentPtr,
                                                normalPtr,
                                                uv0Ptr,
                                                out boundsCenter,
                                                out boundsSize);

            if (generatedMesh.uv0 != null)
            {
                uv0Handle.Free();
            }
            if (generatedMesh.normals != null)
            {
                normalHandle.Free();
            }
            if (generatedMesh.tangents != null)
            {
                tangentHandle.Free();
            }
            positionHandle.Free();
            indicesHandle.Free();

            if (!result ||
                float.IsInfinity(boundsSize.x) || float.IsInfinity(boundsSize.y) || float.IsInfinity(boundsSize.z) ||
                float.IsNaN(boundsSize.x) || float.IsNaN(boundsSize.y) || float.IsNaN(boundsSize.z))
            {
                return(null);
            }

            generatedMesh.bounds = new Bounds(boundsCenter, boundsSize);
            return(generatedMesh);
        }