public override void DoWork()
        {
            ProfilerShort.Begin("MyPrecalcJobPhysicsPrefetch.DoWork");
            try
            {
                if (m_isCancelled)
                {
                    return;
                }

                var geometryData = m_args.TargetPhysics.CreateMesh(m_args.Storage, m_args.GeometryCell);

                if (m_isCancelled)
                {
                    return;
                }

                if (!MyIsoMesh.IsEmpty(geometryData))
                {
                    m_result = m_args.TargetPhysics.CreateShape(geometryData);
                }
            }
            finally
            {
                ProfilerShort.End();
            }
        }
Exemple #2
0
        internal HkBvCompressedMeshShape CreateShape(MyIsoMesh mesh)
        {
            // mk:NOTE This method must be thread safe. Called from worker threads.

            if (mesh == null || mesh.TrianglesCount == 0 || mesh.VerticesCount == 0)
            {
                return((HkBvCompressedMeshShape)HkShape.Empty);
            }

            List <int>     indexList  = new List <int>(mesh.TrianglesCount * 3);
            List <Vector3> vertexList = new List <Vector3>(mesh.VerticesCount);

            for (int i = 0; i < mesh.TrianglesCount; i++)
            {
                indexList.Add(mesh.Triangles[i].VertexIndex0);
                indexList.Add(mesh.Triangles[i].VertexIndex2);
                indexList.Add(mesh.Triangles[i].VertexIndex1);
            }

            // mk:TODO Unify denormalizing of positions with what is in MyIsoMesh.
            var positionOffset = mesh.PositionOffset - m_voxelMap.StorageMin * MyVoxelConstants.VOXEL_SIZE_IN_METRES;
            var positions      = mesh.Positions.GetInternalArray();

            for (int i = 0; i < mesh.VerticesCount; i++)
            {
                vertexList.Add(positions[i] * mesh.PositionScale + positionOffset);
            }
            using (var cellGeometry = new HkGeometry(vertexList, indexList))
            {
                var result = new HkBvCompressedMeshShape(cellGeometry, null, null, HkWeldingType.None, MyPerGameSettings.PhysicsConvexRadius);
                Debug.Assert(result.Base.ReferenceCount == 1);
                return(result);
            }
        }
Exemple #3
0
        private void RequestShapeBlocking(int x, int y, int z, out HkBvCompressedMeshShape shape, out HkReferencePolicy refPolicy)
        {
            ProfilerShort.Begin("MyVoxelPhysicsBody.RequestShapeBlocking");

            const int lod       = 0;
            var       cellCoord = new MyCellCoord(lod, new Vector3I(x, y, z));

            shape = (HkBvCompressedMeshShape)HkShape.Empty;
            // shape must take ownership, otherwise shapes created here will leak, since I can't remove reference
            refPolicy = HkReferencePolicy.TakeOwnership;
            MyPrecalcComponent.QueueJobCancel(m_workTracker, cellCoord.CoordInLod);

            if (m_voxelMap.MarkedForClose)
            {
                ProfilerShort.End();
                return;
            }

            ProfilerShort.Begin("Generating geometry");
            MyIsoMesh geometryData = CreateMesh(m_voxelMap.Storage, cellCoord.CoordInLod);

            ProfilerShort.End();

            if (!MyIsoMesh.IsEmpty(geometryData))
            {
                ProfilerShort.Begin("Shape from geometry");
                shape = CreateShape(geometryData);
                m_needsShapeUpdate = true;
                ProfilerShort.End();
            }

            ProfilerShort.End();
        }
        public override void DoWork()
        {
            ProfilerShort.Begin("MyPrecalcJobPhysicsBatch.DoWork");
            try
            {
                IMyStorage storage = m_targetPhysics.m_voxelMap.Storage;
                foreach (var cell in CellBatch)
                {
                    if (m_isCancelled)
                    {
                        break;
                    }

                    var geometryData = m_targetPhysics.CreateMesh(storage, cell);
                    if (m_isCancelled)
                    {
                        break;
                    }

                    if (!MyIsoMesh.IsEmpty(geometryData))
                    {
                        var meshShape = m_targetPhysics.CreateShape(geometryData);
                        m_newShapes.Add(cell, meshShape);
                    }
                    else
                    {
                        m_newShapes.Add(cell, (HkBvCompressedMeshShape)HkShape.Empty);
                    }
                }
            }
            finally
            {
                ProfilerShort.End();
            }
        }
Exemple #5
0
        public bool TryGetMesh(MyCellCoord cell, out bool isEmpty, out MyIsoMesh nonEmptyMesh)
        {
            bool flag;

            using (this.m_lock.AcquireSharedUsing())
            {
                if (this.IsEmpty(ref cell))
                {
                    isEmpty      = true;
                    nonEmptyMesh = null;
                    flag         = true;
                }
                else
                {
                    ulong key = cell.PackId64();
                    if (this.m_coordinateToMesh.TryGetValue(key, out nonEmptyMesh))
                    {
                        isEmpty = false;
                        flag    = true;
                    }
                    else
                    {
                        isEmpty      = false;
                        nonEmptyMesh = null;
                        flag         = false;
                    }
                }
            }
            return(flag);
        }
        private void ProcessVertex(MyIsoMesh mesh, int vertexIndex, ref BoundingBox localAabb, ref Vector3 positionScale, ref Vector3D positionOffset, out MyVoxelVertex vertex)
        {
            vertex.Position = mesh.Positions[vertexIndex];
            vertex.Normal   = mesh.Normals[vertexIndex];
            vertex.Material = mesh.Materials[vertexIndex];
            vertex.Ambient  = 0f;
            Vertex morph;

            if (m_morphMap.TryGetValue(mesh.Cells[vertexIndex] >> 1, out morph))
            {
                vertex.PositionMorph = morph.Target.Position;
                vertex.NormalMorph   = morph.Target.Normal;
                vertex.MaterialMorph = morph.Target.Material;
            }
            else
            {
                vertex.PositionMorph = vertex.Position;
                vertex.NormalMorph   = vertex.Normal;
                vertex.MaterialMorph = vertex.Material;
            }
            localAabb.Include(vertex.Position * positionScale + positionOffset);
            localAabb.Include(vertex.PositionMorph * positionScale + positionOffset);

            Debug.Assert(vertex.Position.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
            Debug.Assert(vertex.PositionMorph.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
        }
Exemple #7
0
        private void RequestShapeBlockingInternal(int x, int y, int z, out HkBvCompressedMeshShape shape, out HkReferencePolicy refPolicy, bool lod1physics)
        {
            ProfilerShort.Begin("MyVoxelPhysicsBody.RequestShapeBlocking");

            const int lod       = 0;
            var       cellCoord = new MyCellCoord(lod, new Vector3I(x, y, z));

            shape = (HkBvCompressedMeshShape)HkShape.Empty;
            // shape must take ownership, otherwise shapes created here will leak, since I can't remove reference
            refPolicy = HkReferencePolicy.TakeOwnership;
            MyPrecalcComponent.QueueJobCancel(m_workTracker, cellCoord.CoordInLod);

            if (m_voxelMap.MarkedForClose)
            {
                ProfilerShort.End();
                return;
            }
            //BoundingBoxD aabb;
            //MyVoxelCoordSystems.GeometryCellCoordToWorldAABB(m_voxelMap.PositionLeftBottomCorner, ref cellCoord.CoordInLod, out aabb);
            //MyRenderProxy.DebugDrawAABB(aabb, Color.Red, 1, 1, false);
            ProfilerShort.Begin("Generating geometry");
            MyIsoMesh geometryData = CreateMesh(m_voxelMap.Storage, cellCoord.CoordInLod, lod1physics);

            ProfilerShort.End();

            if (!MyIsoMesh.IsEmpty(geometryData))
            {
                ProfilerShort.Begin("Shape from geometry");
                shape = CreateShape(geometryData);
                m_needsShapeUpdate = true;
                ProfilerShort.End();
            }

            ProfilerShort.End();
        }
        private void ProcessHighVertex(MyIsoMesh mesh, int vertexIndex, ref MyClipmapCellMeshMetadata meta, out MyVoxelVertex vertex)
        {
            vertex               = new MyVoxelVertex();
            vertex.Position      = mesh.Positions[vertexIndex];
            vertex.Normal        = mesh.Normals[vertexIndex];
            vertex.Material      = mesh.Materials[vertexIndex];
            vertex.Ambient       = mesh.Ambient[vertexIndex];
            vertex.Cell          = mesh.Cells[vertexIndex];
            vertex.PositionMorph = vertex.Position;
            vertex.NormalMorph   = vertex.Normal;
            vertex.MaterialMorph = vertex.Material;
            vertex.AmbientMorph  = vertex.Ambient;


            //Vertex morph;
            //Vector3I lowerLodCell = (mesh.Cells[vertexIndex]) >> 1;

            //if (m_morphMap.TryGetValue(lowerLodCell, out morph))
            //{
            //    vertex.PositionMorph = morph.Target.Position;
            //    vertex.NormalMorph = morph.Target.Normal;
            //    vertex.MaterialMorph = morph.Target.Material;
            //    vertex.AmbientMorph = morph.Target.Ambient;
            //}
            //else
            //{

            //}

            //if (m_lowVertices.Count > 0)
            //{

            //    float closestDistance = float.MaxValue;
            //    int closestLowVertex = -1;
            //    for (int i = 0; i < m_lowVertices.Count; i++)
            //    {
            //        float dist = Vector3.DistanceSquared(vertex.Position, m_lowVertices[i].Target.Position);
            //        if (dist < closestDistance)
            //        {
            //            closestDistance = dist;
            //            closestLowVertex = i;
            //        }
            //    }

            //    vertex.PositionMorph = m_lowVertices[closestLowVertex].Target.Position;
            //    vertex.NormalMorph = m_lowVertices[closestLowVertex].Target.Normal;
            //    vertex.MaterialMorph = m_lowVertices[closestLowVertex].Target.Material;
            //    vertex.AmbientMorph = m_lowVertices[closestLowVertex].Target.Ambient;

            //    m_lowToHighMapping[closestLowVertex].Add(vertexIndex);
            //    m_highToLowMapping.Add(closestLowVertex);
            //}

            m_highVertices.Add(vertex);
        }
        private void EnsureMorphTargetExists(MyPrecalcJobRender.Args args, MyIsoMesh highResMesh)
        {
            // Ensure as many (ideally all) vertices have some mapping prepared.
            // This is here to resolve any missing parent only once for each vertex (main loop can visit vertices for each triangle they appear in).
            //var geometryData = highResMesh;
            for (int i = 0; i < highResMesh.VerticesCount; ++i)
            {
                Vector3 highResPosition = highResMesh.Positions[i];
                Vertex  lowResVertex;

                Vector3I vertexCell = highResMesh.Cells[i] >> 1;
                if (!m_morphMap.TryGetValue(vertexCell, out lowResVertex))
                {
                    float   scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << args.Cell.Lod);
                    Vector3 cell  = highResPosition / scale;
                    cell *= 0.5f;
                    scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << (args.Cell.Lod + 1));
                    Vector3  lowResPosition    = cell * scale;
                    var      cellMin           = vertexCell;
                    var      cellMax           = vertexCell + 1; // usually I need to find parent in this direction
                    float    nearestDist       = float.PositiveInfinity;
                    int      nearestDistManhat = int.MaxValue;
                    Vector3I?nearestCell       = null;
                    for (var it = new Vector3I.RangeIterator(ref cellMin, ref cellMax); it.IsValid(); it.MoveNext())
                    {
                        Vertex morph;
                        if (m_morphMap.TryGetValue(it.Current, out morph))
                        {
                            var   tmp        = it.Current - cellMin;
                            int   distManhat = tmp.X + tmp.Y + tmp.Z;
                            float dist       = (morph.Target.Position - lowResPosition).LengthSquared();
                            if (distManhat < nearestDistManhat ||
                                (distManhat == nearestDistManhat && dist < nearestDist))
                            {
                                nearestDist       = dist;
                                nearestDistManhat = distManhat;
                                nearestCell       = it.Current;
                            }
                        }
                    }

                    if (nearestCell.HasValue)
                    {
                        m_morphMap.Add(vertexCell, m_morphMap[nearestCell.Value]);
                    }
                    else
                    {
                        //Debug.Fail("I'm screwed");
                    }
                }
            }
        }
Exemple #10
0
        internal unsafe HkShape CreateShape(MyIsoMesh mesh, bool simple = false)
        {
            // mk:NOTE This method must be thread safe. Called from worker threads.

            if (mesh == null || mesh.TrianglesCount == 0 || mesh.VerticesCount == 0)
            {
                return(HkShape.Empty);
            }

            if (s_indexList.Capacity < mesh.TrianglesCount * 3)
            {
                s_indexList.Capacity = mesh.TrianglesCount * 3;
            }
            if (s_vertexList.Capacity < mesh.VerticesCount)
            {
                s_vertexList.Capacity = mesh.VerticesCount;
            }

            for (int i = 0; i < mesh.TrianglesCount; i++)
            {
                s_indexList.Add(mesh.Triangles[i].VertexIndex0);
                s_indexList.Add(mesh.Triangles[i].VertexIndex2);
                s_indexList.Add(mesh.Triangles[i].VertexIndex1);
            }

            // mk:TODO Unify denormalizing of positions with what is in MyIsoMesh.
            var positionOffset = mesh.PositionOffset - m_voxelMap.StorageMin * MyVoxelConstants.VOXEL_SIZE_IN_METRES;
            var positions      = mesh.Positions.GetInternalArray();

            for (int i = 0; i < mesh.VerticesCount; i++)
            {
                s_vertexList.Add(positions[i] * mesh.PositionScale + positionOffset);
            }
            {
                HkShape result;
                if (simple)
                {
                    result = new HkSimpleMeshShape(s_vertexList, s_indexList);
                }
                else
                {
                    s_cellGeometry.SetGeometry(s_vertexList, s_indexList);
                    result = new HkBvCompressedMeshShape(s_cellGeometry, null, null, HkWeldingType.None,
                                                         MyPerGameSettings.PhysicsConvexRadius);
                }
                Debug.Assert(result.ReferenceCount == 1);
                s_vertexList.Clear();
                s_indexList.Clear();
                return(result);
            }
        }
        public override void DoWork()
        {
            ProfilerShort.Begin("MyPrecalcJobRender.DoWork");
            try
            {
                if (m_isCancelled)
                {
                    return;
                }

                m_metadata.Cell      = m_args.Cell;
                m_metadata.LocalAabb = BoundingBox.CreateInvalid();

                var cellSize = MyVoxelCoordSystems.RenderCellSizeInLodVoxels(m_args.Cell.Lod);
                var min      = m_args.Cell.CoordInLod * cellSize;
                var max      = min + cellSize - 1
                               + 1 // overlap to neighbor so geometry is stitched together within same LOD
                               + 1 // extra overlap so there are more vertices for mapping to parent LOD
                               + 1 // for eg. 9 vertices in row we need 9 + 1 samples (voxels)
                ;

                MyIsoMesh highResMesh = MyPrecalcComponent.IsoMesher.Precalc(m_args.Storage, m_args.Cell.Lod, min, max, true, true);

                if (m_isCancelled || highResMesh == null)
                {
                    return;
                }

                MyIsoMesh lowResMesh = null;

                // Less detailed mesh for vertex morph targets
                min >>= 1;
                max >>= 1;
                min  -= 1;
                max  += 1;
                // lowResMesh = MyPrecalcComponent.IsoMesher.Precalc(m_args.Storage, m_args.Cell.Lod + 1, min, max, true, true);

                if (m_isCancelled)
                {
                    return;
                }

                RenderCellBuilder.BuildCell(m_args, highResMesh, lowResMesh, m_batches, out m_metadata);
            }
            finally
            {
                ProfilerShort.End();
            }
        }
Exemple #12
0
        private void ProcessHighVertex(MyIsoMesh mesh, int vertexIndex, out MyVoxelVertex vertex)
        {
            vertex               = new MyVoxelVertex();
            vertex.Position      = mesh.Positions[vertexIndex];
            vertex.Normal        = mesh.Normals[vertexIndex];
            vertex.Material      = mesh.Materials[vertexIndex];
            vertex.Ambient       = mesh.Ambient[vertexIndex];
            vertex.Cell          = mesh.Cells[vertexIndex];
            vertex.PositionMorph = vertex.Position;
            vertex.NormalMorph   = vertex.Normal;
            vertex.MaterialMorph = vertex.Material;
            vertex.AmbientMorph  = vertex.Ambient;

            m_highVertices.Add(vertex);
        }
Exemple #13
0
        private void RequestShapeBlockingInternal(int x, int y, int z, out HkShape shape, out HkReferencePolicy refPolicy, bool lod1physics)
        {
            ProfilerShort.Begin("MyVoxelPhysicsBody.RequestShapeBlocking");

            if (!m_bodiesInitialized)
            {
                CreateRigidBodies();
            }

            int lod       = lod1physics ? 1 : 0;
            var cellCoord = new MyCellCoord(lod, new Vector3I(x, y, z));

            shape = HkShape.Empty;
            // shape must take ownership, otherwise shapes created here will leak, since I can't remove reference
            refPolicy = HkReferencePolicy.TakeOwnership;
            //MyPrecalcComponent.QueueJobCancel(m_workTracker, cellCoord);
            if (m_voxelMap.MarkedForClose)
            {
                ProfilerShort.End();
                return;
            }
            if (MyDebugDrawSettings.DEBUG_DRAW_REQUEST_SHAPE_BLOCKING)
            {
                BoundingBoxD aabb;
                MyVoxelCoordSystems.GeometryCellCoordToWorldAABB(m_voxelMap.PositionLeftBottomCorner, ref cellCoord, out aabb);
                MyRenderProxy.DebugDrawAABB(aabb, lod1physics ? Color.Yellow : Color.Red, 1, 1, true);
            }
            ProfilerShort.Begin("Generating geometry");
            MyIsoMesh geometryData = CreateMesh(m_voxelMap.Storage, cellCoord);

            ProfilerShort.End();

            if (!MyIsoMesh.IsEmpty(geometryData))
            {
                ProfilerShort.Begin("Shape from geometry");
                shape = CreateShape(geometryData, true);
                shape.AddReference();
                var args = new MyPrecalcJobPhysicsPrefetch.Args()
                {
                    GeometryCell = cellCoord, TargetPhysics = this, Tracker = m_workTracker, SimpleShape = shape
                };
                MyPrecalcJobPhysicsPrefetch.Start(args);
                m_needsShapeUpdate = true;
                ProfilerShort.End();
            }

            ProfilerShort.End();
        }
Exemple #14
0
 public void SetMesh(MyCellCoord cell, MyIsoMesh mesh)
 {
     if (cell.Lod == 0)
     {
         using (this.m_lock.AcquireExclusiveUsing())
         {
             if (mesh == null)
             {
                 this.SetEmpty(ref cell, true);
             }
             else
             {
                 ulong num = cell.PackId64();
                 this.m_coordinateToMesh[num] = mesh;
             }
         }
     }
 }
        public bool TryGetMesh(MyCellCoord cell, out bool isEmpty, out MyIsoMesh nonEmptyMesh)
        {
            using (m_lock.AcquireSharedUsing())
            {
                if (IsEmpty(ref cell))
                {
                    isEmpty      = true;
                    nonEmptyMesh = null;
                    return(true);
                }

                UInt64 key = cell.PackId64();
                if (m_coordinateToMesh.TryGetValue(key, out nonEmptyMesh))
                {
                    isEmpty = false;
                    return(true);
                }

                isEmpty      = default(bool);
                nonEmptyMesh = default(MyIsoMesh);
                return(false);
            }
        }
        public void SetMesh(MyCellCoord cell, MyIsoMesh mesh)
        {
            // Don't store anything but the most detailed lod (used in physics and raycasts).
            // This cache is mostly supposed to help physics and raycasts, not render.
            if (cell.Lod != 0)
            {
                return;
            }

            MyPrecalcComponent.AssertUpdateThread();
            using (m_lock.AcquireExclusiveUsing())
            {
                if (mesh != null)
                {
                    var key = cell.PackId64();
                    m_coordinateToMesh[key] = mesh;
                }
                else
                {
                    SetEmpty(ref cell, true);
                }
            }
        }
        public override void DoWork()
        {
            ProfilerShort.Begin("MyPrecalcJobPhysicsPrefetch.DoWork");
            //try
            {
                if (m_isCancelled)
                {
                    ProfilerShort.End();
                    return;
                }

                if (m_args.Storage != null)
                {
                    var geometryData = m_args.TargetPhysics.CreateMesh(m_args.Storage, m_args.GeometryCell);

                    if (m_isCancelled)
                    {
                        ProfilerShort.End();
                        return;
                    }

                    if (!MyIsoMesh.IsEmpty(geometryData))
                    {
                        m_result = m_args.TargetPhysics.CreateShape(geometryData);
                    }
                }
                else
                {
                    m_result = m_args.TargetPhysics.BakeCompressedMeshShape((HkSimpleMeshShape)m_args.SimpleShape);
                    m_args.SimpleShape.RemoveReference();
                }
            }
            //finally
            {
                ProfilerShort.End();
            }
        }
Exemple #18
0
        private void ProcessLowMesh(MyIsoMesh highResMesh, MyIsoMesh lowResMesh)
        {
            ProfilerShort.Begin("ProcessLowMesh");
            if (lowResMesh != null)
            {
                /*
                 * Derived transformation of normalized coordinates from low res mesh to high res mesh.
                 * _l is for low res, _h for high res, x is vertex position
                 * x = x_l * scale_l + offset_l
                 * x_h = (x - offset_h) / scale_h
                 * x_h = ((x_l * scale_l + offset_l) - offset_h) / scale_h
                 * x_h = (x_l * scale_l + offset_l - offset_h) / scale_h
                 * x_h = x_l * (scale_l / scale_h) + ((offset_l - offset_h) / scale_h)
                 */
                Vector3 morphOffset, morphScale;
                morphScale  = lowResMesh.PositionScale / highResMesh.PositionScale;
                morphOffset = (Vector3)(lowResMesh.PositionOffset - highResMesh.PositionOffset) / highResMesh.PositionScale;
                for (int i = 0; i < lowResMesh.VerticesCount; ++i)
                {
                    var vertex = new Vertex
                    {
                        Target = new MorphData
                        {
                            Position = lowResMesh.Positions[i] * morphScale + morphOffset,
                            Normal   = lowResMesh.Normals[i],
                            Material = lowResMesh.Materials[i],
                            Ambient  = lowResMesh.Ambient[i],
                        },
                        Cell = lowResMesh.Cells[i],
                    };

                    m_lowVertices.Add(vertex);
                    m_morphMap[vertex.Cell] = vertex;
                }
            }
            ProfilerShort.End();
        }
Exemple #19
0
 public static bool IsEmpty(MyIsoMesh self)
 {
     return self == null || self.Triangles.Count == 0;
 }
        internal unsafe HkShape CreateShape(MyIsoMesh mesh, bool simple = false)
        {
            // mk:NOTE This method must be thread safe. Called from worker threads.

            if (mesh == null || mesh.TrianglesCount == 0 || mesh.VerticesCount == 0)
                return HkShape.Empty;

            if (s_indexList.Capacity < mesh.TrianglesCount * 3)
                s_indexList.Capacity = mesh.TrianglesCount * 3;
            if (s_vertexList.Capacity < mesh.VerticesCount)
                s_vertexList.Capacity = mesh.VerticesCount;

            for (int i = 0; i < mesh.TrianglesCount; i++)
            {
                s_indexList.Add(mesh.Triangles[i].VertexIndex0);
                s_indexList.Add(mesh.Triangles[i].VertexIndex2);
                s_indexList.Add(mesh.Triangles[i].VertexIndex1);
            }

            // mk:TODO Unify denormalizing of positions with what is in MyIsoMesh.
            var positionOffset = mesh.PositionOffset - m_voxelMap.StorageMin * MyVoxelConstants.VOXEL_SIZE_IN_METRES;
            var positions = mesh.Positions.GetInternalArray();
            for (int i = 0; i < mesh.VerticesCount; i++)
            {
                s_vertexList.Add(positions[i] * mesh.PositionScale + positionOffset);
            }
            {
                HkShape result;
                if (simple)
                {
                    result = new HkSimpleMeshShape(s_vertexList, s_indexList);
                }
                else
                {
                    s_cellGeometry.SetGeometry(s_vertexList, s_indexList);
                    result = new HkBvCompressedMeshShape(s_cellGeometry, null, null, HkWeldingType.None,
                        MyPerGameSettings.PhysicsConvexRadius);

                }
                Debug.Assert(result.ReferenceCount == 1);
                s_vertexList.Clear();
                s_indexList.Clear();
                return result;
            }
        }
        internal void BuildCell(
            MyPrecalcJobRender.Args args,
            MyIsoMesh highResMesh,
            MyIsoMesh lowResMesh,
            List <MyClipmapCellBatch> outBatches,
            out MyClipmapCellMeshMetadata meta)
        {
            Debug.Assert(highResMesh != null);

            meta.Cell           = args.Cell;
            meta.PositionOffset = highResMesh.PositionOffset;
            meta.PositionScale  = highResMesh.PositionScale;
            meta.LocalAabb      = BoundingBox.CreateInvalid();

            m_lowVertices.Clear();
            m_highVertices.Clear();
            m_lowToHighMapping.Clear();
            m_highToLowMapping.Clear();
            m_highTriangles.Clear();


            ProcessLowMesh(highResMesh, lowResMesh);

            //  Increase lookup count, so we will think that all vertices in helper arrays are new
            foreach (var lookup in SM_BatchLookups.Values)
            {
                lookup.ResetBatch();
            }

            //for (int i = 0; i < highResMesh.TrianglesCount; i++)
            //{
            //    var v0 = highResMesh.Triangles[i].VertexIndex0;
            //    var v1 = highResMesh.Triangles[i].VertexIndex1;
            //    var v2 = highResMesh.Triangles[i].VertexIndex2;

            //    MyVoxelVertex vertex;
            //    ProcessHighVertex(highResMesh, v0, ref meta, out vertex);
            //    ProcessHighVertex(highResMesh, v1, ref meta, out vertex);
            //    ProcessHighVertex(highResMesh, v2, ref meta, out vertex);

            //    m_highTriangles.Add(new MyVoxelTriangle()
            //    {
            //        VertexIndex0 = (ushort)(i * 3),
            //        VertexIndex1 = (ushort)(i * 3 + 1),
            //        VertexIndex2 = (ushort)(i * 3 + 2),
            //    });
            //}

            for (int i = 0; i < highResMesh.TrianglesCount; i++)
            {
                m_highTriangles.Add(highResMesh.Triangles[i]);
            }
            for (int i = 0; i < highResMesh.VerticesCount; i++)
            {
                MyVoxelVertex vertex;
                ProcessHighVertex(highResMesh, i, ref meta, out vertex);
            }

            if (lowResMesh != null)
            {
                //Closest vertex

                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    float ldist = float.MaxValue;
                    int   bestV = -1;

                    for (int l = 0; l < m_lowVertices.Count; l++)
                    {
                        var dist = Vector3.DistanceSquared(m_lowVertices[l].Target.Position, m_highVertices[i].Position);
                        if (dist < ldist)
                        {
                            ldist = dist;
                            bestV = l;
                        }
                    }

                    var vtx = m_highVertices[i];
                    vtx.PositionMorph = m_lowVertices[bestV].Target.Position;
                    vtx.Normal        = m_lowVertices[bestV].Target.Normal;
                    vtx.Material      = m_lowVertices[bestV].Target.Material;
                    vtx.Ambient       = m_lowVertices[bestV].Target.Ambient;
                    m_highVertices[i] = vtx;
                }



                ////



                //HashSet<int> alreadySetHighTris = new HashSet<int>();

                ////all low tris must have at least one tri from high set, otherwise holes appear.
                //for (int l = 0; l < lowResMesh.TrianglesCount; l++)
                //{
                //    float triDist = float.MaxValue;
                //    int bestT = -1;

                //    for (int i = 0; i < m_highTriangles.Count; i++)
                //    {
                //        if (alreadySetHighTris.Contains(i))
                //            continue;

                //        float dist = 0;
                //        dist += Vector3.DistanceSquared(m_highVertices[m_highTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position);
                //        dist += Vector3.DistanceSquared(m_highVertices[m_highTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position);
                //        dist += Vector3.DistanceSquared(m_highVertices[m_highTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position);

                //        if (dist < triDist)
                //        {
                //            triDist = dist;
                //            bestT = i;
                //        }
                //    }

                //    if (bestT == -1)
                //    {
                //        //Happens when LOD0 has less tris than LOD1
                //        bestT = 0;
                //    }

                //    alreadySetHighTris.Add(bestT);

                //    var v0 = m_highVertices[m_highTriangles[bestT].VertexIndex0];
                //    v0.PositionMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position;
                //    v0.NormalMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Normal;
                //    v0.AmbientMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Ambient;
                //    m_highVertices[m_highTriangles[bestT].VertexIndex0] = v0;

                //    var v1 = m_highVertices[m_highTriangles[bestT].VertexIndex1];
                //    v1.PositionMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position;
                //    v1.NormalMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Normal;
                //    v1.AmbientMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Ambient;
                //    m_highVertices[m_highTriangles[bestT].VertexIndex1] = v1;

                //    var v2 = m_highVertices[m_highTriangles[bestT].VertexIndex2];
                //    v2.PositionMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position;
                //    v2.NormalMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Normal;
                //    v2.AmbientMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Ambient;
                //    m_highVertices[m_highTriangles[bestT].VertexIndex2] = v2;
                //}


                //List<MyVoxelTriangle> restHighTriangles = new List<MyVoxelTriangle>(m_highTriangles);
                //List<int> toRemove = new List<int>();
                //foreach (var i in alreadySetHighTris)
                //{
                //    toRemove.Add(i);
                //}
                //toRemove.Sort();

                //for (int i = toRemove.Count - 1; i >= 0; i--)
                //{
                //    restHighTriangles.RemoveAt(toRemove[i]);
                //}



                //for (int i = 0; i < restHighTriangles.Count; i++)
                //{
                //    float triDist = float.MaxValue;
                //    int bestT = -1;

                //    int swtch = 0;


                //    for (int l = 0; l < lowResMesh.TrianglesCount; l++)
                //    {
                //        float dist = 0;
                //        dist += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position);
                //        dist += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position);
                //        dist += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position);

                //        float dist1 = 0;
                //        dist1 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position);
                //        dist1 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position);
                //        dist1 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position);

                //        float dist2 = 0;
                //        dist2 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position);
                //        dist2 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position);
                //        dist2 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position);

                //        int sw = 0;

                //        if (dist1 < dist && dist1 < dist2)
                //        {
                //            dist = dist1;
                //            sw = 1;
                //        }

                //        if (dist2 < dist && dist2 < dist1)
                //        {
                //            dist = dist2;
                //            sw = 2;
                //        }

                //        if (dist < triDist)
                //        {
                //            triDist = dist;
                //            bestT = l;
                //            swtch = sw;
                //        }
                //    }


                //    //bestT = i % lowResMesh.TrianglesCount;
                //    //bestT = MyUtils.GetRandomInt(lowResMesh.TrianglesCount);

                //    int vi0 = lowResMesh.Triangles[bestT].VertexIndex0;
                //    int vi1 = lowResMesh.Triangles[bestT].VertexIndex1;
                //    int vi2 = lowResMesh.Triangles[bestT].VertexIndex2;

                //    if (swtch == 1)
                //    {
                //        vi0 = lowResMesh.Triangles[bestT].VertexIndex1;
                //        vi1 = lowResMesh.Triangles[bestT].VertexIndex2;
                //        vi2 = lowResMesh.Triangles[bestT].VertexIndex0;
                //    }

                //    if (swtch == 2)
                //    {
                //        vi0 = lowResMesh.Triangles[bestT].VertexIndex2;
                //        vi1 = lowResMesh.Triangles[bestT].VertexIndex0;
                //        vi2 = lowResMesh.Triangles[bestT].VertexIndex1;
                //    }

                //    var v0 = m_highVertices[restHighTriangles[i].VertexIndex0];
                //    v0.PositionMorph = m_lowVertices[vi0].Target.Position;
                //    v0.NormalMorph = m_lowVertices[vi0].Target.Normal;
                //    v0.AmbientMorph = m_lowVertices[vi0].Target.Ambient;
                //    m_highVertices[restHighTriangles[i].VertexIndex0] = v0;

                //    var v1 = m_highVertices[restHighTriangles[i].VertexIndex1];
                //    v1.PositionMorph = m_lowVertices[vi1].Target.Position;
                //    v1.NormalMorph = m_lowVertices[vi1].Target.Normal;
                //    v1.AmbientMorph = m_lowVertices[vi1].Target.Ambient;
                //    m_highVertices[restHighTriangles[i].VertexIndex1] = v1;

                //    var v2 = m_highVertices[restHighTriangles[i].VertexIndex2];
                //    v2.PositionMorph = m_lowVertices[vi2].Target.Position;
                //    v2.NormalMorph = m_lowVertices[vi2].Target.Normal;
                //    v2.AmbientMorph = m_lowVertices[vi2].Target.Ambient;
                //    m_highVertices[restHighTriangles[i].VertexIndex2] = v2;

                //}

                ////add low lod
                //for (int i = 0; i < lowResMesh.TrianglesCount; i++)
                //{
                //    var lt = lowResMesh.Triangles[i];

                //    m_highTriangles.Add(new MyVoxelTriangle()
                //    {
                //        VertexIndex0 = (ushort)(lt.VertexIndex0 + m_highVertices.Count),
                //        VertexIndex1 = (ushort)(lt.VertexIndex1 + m_highVertices.Count),
                //        VertexIndex2 = (ushort)(lt.VertexIndex2 + m_highVertices.Count),
                //    }
                //    );
                //}

                //for (int i = 0; i < m_lowVertices.Count; i++)
                //{
                //    var vertex = new MyVoxelVertex();
                //    vertex.Position = m_lowVertices[i].Target.Position;
                //    vertex.Normal = m_lowVertices[i].Target.Normal;
                //    vertex.Material = m_lowVertices[i].Target.Material;
                //    vertex.Ambient = 0;
                //    vertex.PositionMorph = vertex.Position;
                //    vertex.NormalMorph = vertex.Normal;
                //    vertex.MaterialMorph = vertex.Material;
                //    vertex.AmbientMorph = vertex.Ambient;
                //    m_highVertices.Add(vertex);
                //}


                //    List<MyVoxelTriangle> newTriangles = new List<MyVoxelTriangle>();

                //    for (int i = 0; i < m_highTriangles.Count; i++)
                //    {
                //        MyVoxelVertex v0 = m_highVertices[m_highTriangles[i].VertexIndex0];
                //        MyVoxelVertex v1 = m_highVertices[m_highTriangles[i].VertexIndex1];
                //        MyVoxelVertex v2 = m_highVertices[m_highTriangles[i].VertexIndex2];

                //        for (int v = 0; v < m_highVertices.Count; v++)
                //        {
                //            if (v0.Position == m_highVertices[v].Position)
                //            {
                //                if (v0.PositionMorph == m_highVertices[v].PositionMorph)
                //                {
                //                    var t = m_highTriangles[i];
                //                    t.VertexIndex0 = (ushort)v;
                //                    m_highTriangles[i] = t;
                //                    break;
                //                }
                //                else
                //                {
                //                    var vert1 = m_highVertices[m_highTriangles[i].VertexIndex1];
                //                    var vert2 = m_highVertices[m_highTriangles[i].VertexIndex2];

                //                    vert1.Position = m_highVertices[v].Position;
                //                    vert2.Position = m_highVertices[v].Position;

                //                    m_highVertices.Add(vert1);
                //                    m_highVertices.Add(vert2);

                //                    newTriangles.Add(new MyVoxelTriangle()
                //                    {
                //                        VertexIndex0 = (ushort)v,
                //                        VertexIndex1 = (ushort)(m_highVertices.Count - 2),
                //                        VertexIndex2 = (ushort)(m_highVertices.Count - 1)
                //                    });
                //                }
                //            }
                //        }

                //        for (int v = 0; v < m_highVertices.Count; v++)
                //        {
                //            if (v1.Position == m_highVertices[v].Position)
                //            {
                //                if (v1.PositionMorph == m_highVertices[v].PositionMorph)
                //                {
                //                    var t = m_highTriangles[i];
                //                    t.VertexIndex1 = (ushort)v;
                //                    m_highTriangles[i] = t;
                //                    break;
                //                }
                //                else
                //                {
                //                    var vert0 = m_highVertices[m_highTriangles[i].VertexIndex0];
                //                    var vert2 = m_highVertices[m_highTriangles[i].VertexIndex2];

                //                    vert0.Position = m_highVertices[v].Position;
                //                    vert2.Position = m_highVertices[v].Position;

                //                    m_highVertices.Add(vert0);
                //                    m_highVertices.Add(vert2);

                //                    newTriangles.Add(new MyVoxelTriangle()
                //                    {
                //                        VertexIndex0 = (ushort)(m_highVertices.Count - 2),
                //                        VertexIndex1 = (ushort)v,
                //                        VertexIndex2 = (ushort)(m_highVertices.Count - 1)
                //                    });
                //                }

                //            }
                //        }

                //        for (int v = 0; v < m_highVertices.Count; v++)
                //        {
                //            if (v2.Position == m_highVertices[v].Position)
                //            {
                //                if (v2.PositionMorph == m_highVertices[v].PositionMorph)
                //                {
                //                    var t = m_highTriangles[i];
                //                    t.VertexIndex2 = (ushort)v;
                //                    m_highTriangles[i] = t;
                //                    break;
                //                }
                //                else
                //                {
                //                    var vert0 = m_highVertices[m_highTriangles[i].VertexIndex0];
                //                    var vert1 = m_highVertices[m_highTriangles[i].VertexIndex1];

                //                    vert0.Position = m_highVertices[v].Position;
                //                    vert1.Position = m_highVertices[v].Position;

                //                    m_highVertices.Add(vert0);
                //                    m_highVertices.Add(vert1);

                //                    newTriangles.Add(new MyVoxelTriangle()
                //                    {
                //                        VertexIndex0 = (ushort)(m_highVertices.Count - 2),
                //                        VertexIndex1 = (ushort)(m_highVertices.Count - 1),
                //                        VertexIndex2 = (ushort)v
                //                    });
                //                }

                //            }
                //        }
                //    }


                //    foreach (var t in newTriangles)
                //    {
                //        m_highTriangles.Add(t);
                //    }


                float largestDistance = float.MinValue;
                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    MyVoxelVertex vertex = m_highVertices[i];
                    float         p1     = vertex.Position.AbsMax();
                    if (p1 > largestDistance)
                    {
                        largestDistance = p1;
                    }
                    float p2 = vertex.PositionMorph.AbsMax();
                    if (p2 > largestDistance)
                    {
                        largestDistance = p2;
                    }
                }


                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    MyVoxelVertex vertex = m_highVertices[i];

                    vertex.Position      /= largestDistance;
                    vertex.PositionMorph /= largestDistance;

                    m_highVertices[i] = vertex;
                }

                meta.PositionScale *= largestDistance;
            }
            else
            {
            }



            for (int i = 0; i < m_highVertices.Count; i++)
            {
                MyVoxelVertex vertex = m_highVertices[i];

                meta.LocalAabb.Include(vertex.Position * meta.PositionScale + meta.PositionOffset);
                meta.LocalAabb.Include(vertex.PositionMorph * meta.PositionScale + meta.PositionOffset);

                Debug.Assert(vertex.Position.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
                Debug.Assert(vertex.PositionMorph.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
            }


            for (int i = 0; i < m_highTriangles.Count; i++)
            {
                MyVoxelTriangle srcTriangle = m_highTriangles[i];
                MyVoxelVertex   vertex0, vertex1, vertex2;
                vertex0 = m_highVertices[srcTriangle.VertexIndex0];
                vertex1 = m_highVertices[srcTriangle.VertexIndex1];
                vertex2 = m_highVertices[srcTriangle.VertexIndex2];

                if (vertex0.Material == vertex1.Material &&
                    vertex0.Material == vertex2.Material &&
                    vertex0.Material == vertex0.MaterialMorph &&
                    vertex0.Material == vertex1.MaterialMorph &&
                    vertex0.Material == vertex2.MaterialMorph)
                { // single material
                    var matIdx = vertex0.Material;

                    //  This is single-texture triangleVertexes, so we can choose material from any edge
                    SingleMaterialHelper materialHelper;
                    if (!SM_Helpers.TryGetValue(matIdx, out materialHelper))
                    {
                        if (!SM_HelperPool.TryDequeue(out materialHelper))
                        {
                            materialHelper = new SingleMaterialHelper();
                        }
                        materialHelper.Material = matIdx;
                        SM_Helpers.Add(matIdx, materialHelper);
                    }

                    VertexInBatchLookup batchLookup;
                    if (!SM_BatchLookups.TryGetValue(matIdx, out batchLookup))
                    {
                        if (!SM_BatchLookupPool.TryDequeue(out batchLookup))
                        {
                            batchLookup = new VertexInBatchLookup();
                        }
                        SM_BatchLookups.Add(matIdx, batchLookup);
                    }

                    AddVertexToBuffer(materialHelper, ref vertex0, batchLookup, srcTriangle.VertexIndex0);
                    AddVertexToBuffer(materialHelper, ref vertex1, batchLookup, srcTriangle.VertexIndex1);
                    AddVertexToBuffer(materialHelper, ref vertex2, batchLookup, srcTriangle.VertexIndex2);

                    //  Add indices
                    int nextTriangleIndex = materialHelper.IndexCount;
                    materialHelper.Indices[nextTriangleIndex + 0] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex0);
                    materialHelper.Indices[nextTriangleIndex + 1] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex1);
                    materialHelper.Indices[nextTriangleIndex + 2] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex2);
                    materialHelper.IndexCount += 3;

                    if ((materialHelper.VertexCount >= MAX_VERTICES_COUNT_STOP) ||
                        (materialHelper.IndexCount >= MAX_INDICES_COUNT_STOP))
                    {
                        //  If this batch is almost full (or is full), we end it and start with new one
                        EndSingleMaterial(materialHelper, outBatches);
                    }
                }
                else
                {
                    Vector3I materials          = GetMaterials(ref vertex0, ref vertex1, ref vertex2);
                    var      voxelMaterialCount = MyDefinitionManager.Static.VoxelMaterialCount;
                    int      id = materials.X + voxelMaterialCount * (materials.Y + materials.Z * voxelMaterialCount);

                    // Assign current material
                    MultiMaterialHelper helper = null;
                    if (!MM_Helpers.TryGetValue(id, out helper))
                    {
                        if (!MM_HelperPool.TryDequeue(out helper))
                        {
                            helper = new MultiMaterialHelper();
                        }
                        helper.Material0 = materials.X;
                        helper.Material1 = materials.Y;
                        helper.Material2 = materials.Z;
                        MM_Helpers.Add(id, helper);
                    }

                    helper.AddVertex(ref vertex0);
                    helper.AddVertex(ref vertex1);
                    helper.AddVertex(ref vertex2);

                    if (helper.Vertices.Count >= MAX_VERTICES_COUNT_STOP)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                }
            }

            { //renderCell.End();
                foreach (var helper in SM_Helpers.Values)
                {
                    Debug.Assert(helper != null);
                    if (helper.IndexCount > 0)
                    {
                        EndSingleMaterial(helper, outBatches);
                    }
                    helper.IndexCount  = 0;
                    helper.VertexCount = 0;
                    SM_HelperPool.Enqueue(helper);
                }
                SM_Helpers.Clear();

                foreach (var helper in MM_Helpers.Values)
                {
                    if (helper.Vertices.Count > 0)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                    helper.Vertices.Clear();
                    MM_HelperPool.Enqueue(helper);
                }
                MM_Helpers.Clear();

                foreach (var lookup in SM_BatchLookups.Values)
                {
                    SM_BatchLookupPool.Enqueue(lookup);
                }
                SM_BatchLookups.Clear();
            }

            m_morphMap.Clear();
        }
Exemple #22
0
        public override void DoWork()
        {
            ProfilerShort.Begin("MyPrecalcJobRender.DoWork");
            try
            {
                if (m_isCancelled)
                {
                    return;
                }

                m_metadata.Cell      = m_args.Cell;
                m_metadata.LocalAabb = BoundingBox.CreateInvalid();

                var cellSize = MyVoxelCoordSystems.RenderCellSizeInLodVoxels(m_args.Cell.Lod);
                var min      = m_args.Cell.CoordInLod * cellSize - 1;
                var max      = min + cellSize - 1
                               + 1  // overlap to neighbor so geometry is stitched together within same LOD
                               + 1  // extra overlap so there are more vertices for mapping to parent LOD
                               + 1; // for eg. 9 vertices in row we need 9 + 1 samples (voxels)
                //    + 1 // why not
                //  + 1 // martin kroslak approved

                var       clipmapCellId = MyCellCoord.GetClipmapCellHash(m_args.ClipmapId, m_args.Cell.PackId64());
                MyIsoMesh highResMesh   = IsoMeshCache.Read(clipmapCellId);

                if (highResMesh == null)
                {
                    highResMesh = MyPrecalcComponent.IsoMesher.Precalc(m_args.Storage, m_args.Cell.Lod, min, max, true, MyFakes.ENABLE_VOXEL_COMPUTED_OCCLUSION);
                    if (UseIsoCache && highResMesh != null)
                    {
                        IsoMeshCache.Write(clipmapCellId, highResMesh);
                    }
                }

                if (m_isCancelled || highResMesh == null)
                {
                    return;
                }

                MyIsoMesh lowResMesh = null;

                if (m_args.Cell.Lod < 15 && MyFakes.ENABLE_VOXEL_LOD_MORPHING)
                {
                    var nextLodCell = m_args.Cell;
                    nextLodCell.Lod++;
                    clipmapCellId = MyCellCoord.GetClipmapCellHash(m_args.ClipmapId, nextLodCell.PackId64());

                    lowResMesh = IsoMeshCache.Read(clipmapCellId);

                    if (lowResMesh == null)
                    {
                        // Less detailed mesh for vertex morph targets
                        min >>= 1;
                        max >>= 1;
                        min  -= 1;
                        max  += 2;

                        lowResMesh = MyPrecalcComponent.IsoMesher.Precalc(m_args.Storage, m_args.Cell.Lod + 1, min, max, true, MyFakes.ENABLE_VOXEL_COMPUTED_OCCLUSION);

                        if (UseIsoCache && lowResMesh != null)
                        {
                            IsoMeshCache.Write(clipmapCellId, lowResMesh);
                        }
                    }
                }

                if (m_isCancelled)
                {
                    return;
                }

                RenderCellBuilder.BuildCell(m_args, highResMesh, lowResMesh, m_batches, out m_metadata);
            }
            finally
            {
                ProfilerShort.End();
            }
        }
Exemple #23
0
        internal void BuildCell(
            MyPrecalcJobRender.Args args,
            MyIsoMesh highResMesh,
            MyIsoMesh lowResMesh,
            List <MyClipmapCellBatch> outBatches,
            out MyClipmapCellMeshMetadata meta)
        {
            ProfilerShort.Begin("MyRenderCellBuilder.BuildCell");
            Debug.Assert(highResMesh != null);

            meta.Cell           = args.Cell;
            meta.PositionOffset = highResMesh.PositionOffset;
            meta.PositionScale  = highResMesh.PositionScale;
            meta.LocalAabb      = BoundingBox.CreateInvalid();

            m_lowVertices.SetSize(0);
            m_highVertices.SetSize(0);

            ProcessLowMesh(highResMesh, lowResMesh);

            //  Increase lookup count, so we will think that all vertices in helper arrays are new
            foreach (var lookup in SM_BatchLookups.Values)
            {
                lookup.ResetBatch();
            }


            for (int i = 0; i < highResMesh.VerticesCount; i++)
            {
                MyVoxelVertex vertex;
                ProcessHighVertex(highResMesh, i, out vertex);
            }

            if (lowResMesh != null)
            {
                m_highGrid.ClearFast();

                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    Vector3 position = m_highVertices[i].Position;
                    m_highGrid.AddPoint(ref position, i);
                }

                //TODO: Fix ocassional bad triangles on asteroid

                /*
                 * //Closest vertex
                 * for (int l = 0; l < m_lowVertices.Count; l++)
                 * {
                 *  Vector3 targetPosition = m_lowVertices[l].Target.Position;
                 *
                 *  int bestV = -1;
                 *  float ldist = float.MaxValue;
                 *  float startMeters = 1;
                 *  float maxDistance = 10;
                 *
                 *  MyVector3Grid<int>.Enumerator points = default(MyVector3Grid<int>.Enumerator);
                 *  while (startMeters < maxDistance)
                 *  {
                 *      points = m_highGrid.GetPointsCloserThan(ref targetPosition, startMeters);
                 *
                 *      while (points.MoveNext())
                 *      {
                 *          var dist = Vector3.DistanceSquared(targetPosition, m_highVertices[points.Current].Position);
                 *          if (dist < ldist)
                 *          {
                 *              ldist = dist;
                 *              bestV = points.Current;
                 *          }
                 *      }
                 *
                 *      if (bestV != -1)
                 *          break;
                 *
                 *      startMeters += 1;
                 *  }
                 *
                 *  if (bestV != -1)
                 *  {
                 *      var vtx = m_highVertices[bestV];
                 *      vtx.PositionMorph = m_lowVertices[l].Target.Position;
                 *      vtx.NormalMorph = m_lowVertices[l].Target.Normal;
                 *      vtx.MaterialMorph = m_lowVertices[l].Target.Material;
                 *      vtx.AmbientMorph = m_lowVertices[l].Target.Ambient;
                 *      m_highVertices[bestV] = vtx;
                 *  }
                 *  else
                 *  {
                 *  }
                 * }
                 *
                 */

                //Closest vertex
                float largestDistance = float.MinValue;
                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    float ldist = float.MaxValue;
                    int   bestV = -1;

                    for (int l = 0; l < m_lowVertices.Count; l++)
                    {
                        var dist = Vector3.DistanceSquared(m_lowVertices[l].Target.Position, m_highVertices[i].Position);
                        if (dist < ldist)
                        {
                            ldist = dist;
                            bestV = l;
                        }
                    }

                    var highVertex = m_highVertices[i];
                    highVertex.PositionMorph = m_lowVertices[bestV].Target.Position;
                    highVertex.NormalMorph   = m_lowVertices[bestV].Target.Normal;
                    highVertex.MaterialMorph = m_lowVertices[bestV].Target.Material;
                    highVertex.AmbientMorph  = m_lowVertices[bestV].Target.Ambient;

                    float p1 = highVertex.Position.AbsMax();
                    if (p1 > largestDistance)
                    {
                        largestDistance = p1;
                    }
                    float p2 = highVertex.PositionMorph.AbsMax();
                    if (p2 > largestDistance)
                    {
                        largestDistance = p2;
                    }

                    m_highVertices[i] = highVertex;
                }

                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    MyVoxelVertex vertex = m_highVertices[i];

                    vertex.Position      /= largestDistance;
                    vertex.PositionMorph /= largestDistance;

                    m_highVertices[i] = vertex;
                }

                meta.PositionScale *= largestDistance;
            }

            //Create batches
            for (int i = 0; i < m_highVertices.Count; i++)
            {
                MyVoxelVertex vertex = m_highVertices[i];

                meta.LocalAabb.Include(vertex.Position * meta.PositionScale + meta.PositionOffset);
                meta.LocalAabb.Include(vertex.PositionMorph * meta.PositionScale + meta.PositionOffset);

                Debug.Assert(vertex.Position.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
                Debug.Assert(vertex.PositionMorph.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
            }

            for (int i = 0; i < highResMesh.TrianglesCount; i++)
            {
                MyVoxelTriangle srcTriangle = highResMesh.Triangles[i];
                MyVoxelVertex   vertex0     = m_highVertices[srcTriangle.VertexIndex0];
                MyVoxelVertex   vertex1     = m_highVertices[srcTriangle.VertexIndex1];
                MyVoxelVertex   vertex2     = m_highVertices[srcTriangle.VertexIndex2];

                if (vertex0.Material == vertex1.Material &&
                    vertex0.Material == vertex2.Material &&
                    vertex0.Material == vertex0.MaterialMorph &&
                    vertex0.Material == vertex1.MaterialMorph &&
                    vertex0.Material == vertex2.MaterialMorph)
                { // single material
                    var matIdx = vertex0.Material;

                    //  This is single-texture triangleVertexes, so we can choose material from any edge
                    SingleMaterialHelper materialHelper;
                    if (!SM_Helpers.TryGetValue(matIdx, out materialHelper))
                    {
                        if (!SM_HelperPool.TryDequeue(out materialHelper))
                        {
                            materialHelper = new SingleMaterialHelper();
                        }
                        materialHelper.Material = matIdx;
                        SM_Helpers.Add(matIdx, materialHelper);
                    }

                    VertexInBatchLookup batchLookup;
                    if (!SM_BatchLookups.TryGetValue(matIdx, out batchLookup))
                    {
                        if (!SM_BatchLookupPool.TryDequeue(out batchLookup))
                        {
                            batchLookup = new VertexInBatchLookup();
                        }
                        SM_BatchLookups.Add(matIdx, batchLookup);
                    }

                    AddVertexToBuffer(materialHelper, ref vertex0, batchLookup, srcTriangle.VertexIndex0);
                    AddVertexToBuffer(materialHelper, ref vertex1, batchLookup, srcTriangle.VertexIndex1);
                    AddVertexToBuffer(materialHelper, ref vertex2, batchLookup, srcTriangle.VertexIndex2);

                    //  Add indices
                    int nextTriangleIndex = materialHelper.IndexCount;
                    materialHelper.Indices[nextTriangleIndex + 0] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex0);
                    materialHelper.Indices[nextTriangleIndex + 1] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex1);
                    materialHelper.Indices[nextTriangleIndex + 2] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex2);
                    materialHelper.IndexCount += 3;

                    if ((materialHelper.VertexCount >= MAX_VERTICES_COUNT_STOP) ||
                        (materialHelper.IndexCount >= MAX_INDICES_COUNT_STOP))
                    {
                        //  If this batch is almost full (or is full), we end it and start with new one
                        EndSingleMaterial(materialHelper, outBatches);
                    }
                }
                else
                {
                    Vector3I materials = GetMaterials(ref vertex0, ref vertex1, ref vertex2);
                    Debug.Assert(materials.X < 1 << 10, "Too many materials");
                    Debug.Assert(materials.Y < 1 << 10, "Too many materials");
                    Debug.Assert(materials.Z < 1 << 10, "Too many materials");
                    int id = materials.X + (materials.Y + (materials.Z << 10) << 10);

                    // Assign current material
                    MultiMaterialHelper helper = null;
                    if (!MM_Helpers.TryGetValue(id, out helper))
                    {
                        if (!MM_HelperPool.TryDequeue(out helper))
                        {
                            helper = new MultiMaterialHelper();
                        }
                        helper.Material0 = materials.X;
                        helper.Material1 = materials.Y;
                        helper.Material2 = materials.Z;
                        MM_Helpers.Add(id, helper);
                    }

                    helper.AddVertex(ref vertex0);
                    helper.AddVertex(ref vertex1);
                    helper.AddVertex(ref vertex2);

                    if (helper.Vertices.Count >= MAX_VERTICES_COUNT_STOP)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                }
            }

            { //renderCell.End();
                foreach (var helper in SM_Helpers.Values)
                {
                    Debug.Assert(helper != null);
                    if (helper.IndexCount > 0)
                    {
                        EndSingleMaterial(helper, outBatches);
                    }
                    helper.IndexCount  = 0;
                    helper.VertexCount = 0;
                    SM_HelperPool.Enqueue(helper);
                }
                SM_Helpers.Clear();

                foreach (var helper in MM_Helpers.Values)
                {
                    if (helper.Vertices.Count > 0)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                    helper.Vertices.Clear();
                    MM_HelperPool.Enqueue(helper);
                }
                MM_Helpers.Clear();

                foreach (var lookup in SM_BatchLookups.Values)
                {
                    SM_BatchLookupPool.Enqueue(lookup);
                }
                SM_BatchLookups.Clear();
            }

            m_morphMap.Clear();
            meta.BatchCount = outBatches.Count;
            ProfilerShort.End();
        }
        public bool TryGetMesh(MyCellCoord cell, out bool isEmpty, out MyIsoMesh nonEmptyMesh)
        {
            using (m_lock.AcquireSharedUsing())
            {
                if (IsEmpty(ref cell))
                {
                    isEmpty = true;
                    nonEmptyMesh = null;
                    return true;
                }

                UInt64 key = cell.PackId64();
                if (m_coordinateToMesh.TryGetValue(key, out nonEmptyMesh))
                {
                    isEmpty = false;
                    return true;
                }

                isEmpty = default(bool);
                nonEmptyMesh = default(MyIsoMesh);
                return false;
            }
        }
        internal void BuildCell(
            MyPrecalcJobRender.Args args,
            MyIsoMesh highResMesh,
            MyIsoMesh lowResMesh,
            List<MyClipmapCellBatch> outBatches,
            out MyClipmapCellMeshMetadata meta)
        {
            Debug.Assert(highResMesh != null);

            meta.Cell = args.Cell;
            meta.PositionOffset = highResMesh.PositionOffset;
            meta.PositionScale = highResMesh.PositionScale;
            meta.LocalAabb = BoundingBox.CreateInvalid();

            m_lowVertices.Clear();
            m_highVertices.Clear();
            m_lowToHighMapping.Clear();
            m_highToLowMapping.Clear();
            m_highTriangles.Clear();


            ProcessLowMesh(highResMesh, lowResMesh);

            //  Increase lookup count, so we will think that all vertices in helper arrays are new
            foreach (var lookup in SM_BatchLookups.Values)
            {
                lookup.ResetBatch();
            }

            //for (int i = 0; i < highResMesh.TrianglesCount; i++)
            //{
            //    var v0 = highResMesh.Triangles[i].VertexIndex0;
            //    var v1 = highResMesh.Triangles[i].VertexIndex1;
            //    var v2 = highResMesh.Triangles[i].VertexIndex2;

            //    MyVoxelVertex vertex;
            //    ProcessHighVertex(highResMesh, v0, ref meta, out vertex);
            //    ProcessHighVertex(highResMesh, v1, ref meta, out vertex);
            //    ProcessHighVertex(highResMesh, v2, ref meta, out vertex);

            //    m_highTriangles.Add(new MyVoxelTriangle()
            //    {
            //        VertexIndex0 = (ushort)(i * 3),
            //        VertexIndex1 = (ushort)(i * 3 + 1),
            //        VertexIndex2 = (ushort)(i * 3 + 2),
            //    });
            //}

            for (int i = 0; i < highResMesh.TrianglesCount; i++)
            {
                m_highTriangles.Add(highResMesh.Triangles[i]);
            }
            for (int i = 0; i < highResMesh.VerticesCount; i++)
            {
                MyVoxelVertex vertex;
                ProcessHighVertex(highResMesh, i, ref meta, out vertex);
            }

            if (lowResMesh != null)
            {
                //Closest vertex

                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    float ldist = float.MaxValue;
                    int bestV = -1;

                    for (int l = 0; l < m_lowVertices.Count; l++)
                    {
                        var dist = Vector3.DistanceSquared(m_lowVertices[l].Target.Position, m_highVertices[i].Position);
                        if (dist < ldist)
                        {
                            ldist = dist;
                            bestV = l;
                        }
                    }

                    var vtx = m_highVertices[i];
                    vtx.PositionMorph = m_lowVertices[bestV].Target.Position;
                    vtx.Normal= m_lowVertices[bestV].Target.Normal;
                    vtx.Material = m_lowVertices[bestV].Target.Material;
                    vtx.Ambient = m_lowVertices[bestV].Target.Ambient;
                    m_highVertices[i] = vtx;
                }



                ////







                //HashSet<int> alreadySetHighTris = new HashSet<int>();

                ////all low tris must have at least one tri from high set, otherwise holes appear. 
                //for (int l = 0; l < lowResMesh.TrianglesCount; l++)
                //{
                //    float triDist = float.MaxValue;
                //    int bestT = -1;

                //    for (int i = 0; i < m_highTriangles.Count; i++)
                //    {
                //        if (alreadySetHighTris.Contains(i))
                //            continue;

                //        float dist = 0;
                //        dist += Vector3.DistanceSquared(m_highVertices[m_highTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position);
                //        dist += Vector3.DistanceSquared(m_highVertices[m_highTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position);
                //        dist += Vector3.DistanceSquared(m_highVertices[m_highTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position);

                //        if (dist < triDist)
                //        {
                //            triDist = dist;
                //            bestT = i;
                //        }
                //    }

                //    if (bestT == -1)
                //    {
                //        //Happens when LOD0 has less tris than LOD1
                //        bestT = 0;
                //    }

                //    alreadySetHighTris.Add(bestT);

                //    var v0 = m_highVertices[m_highTriangles[bestT].VertexIndex0];
                //    v0.PositionMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position;
                //    v0.NormalMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Normal;
                //    v0.AmbientMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Ambient;
                //    m_highVertices[m_highTriangles[bestT].VertexIndex0] = v0;

                //    var v1 = m_highVertices[m_highTriangles[bestT].VertexIndex1];
                //    v1.PositionMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position;
                //    v1.NormalMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Normal;
                //    v1.AmbientMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Ambient;
                //    m_highVertices[m_highTriangles[bestT].VertexIndex1] = v1;

                //    var v2 = m_highVertices[m_highTriangles[bestT].VertexIndex2];
                //    v2.PositionMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position;
                //    v2.NormalMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Normal;
                //    v2.AmbientMorph = m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Ambient;
                //    m_highVertices[m_highTriangles[bestT].VertexIndex2] = v2;
                //}


                //List<MyVoxelTriangle> restHighTriangles = new List<MyVoxelTriangle>(m_highTriangles);
                //List<int> toRemove = new List<int>();
                //foreach (var i in alreadySetHighTris)
                //{
                //    toRemove.Add(i);
                //}
                //toRemove.Sort();

                //for (int i = toRemove.Count - 1; i >= 0; i--)
                //{
                //    restHighTriangles.RemoveAt(toRemove[i]);
                //}



                //for (int i = 0; i < restHighTriangles.Count; i++)
                //{
                //    float triDist = float.MaxValue;
                //    int bestT = -1;

                //    int swtch = 0;


                //    for (int l = 0; l < lowResMesh.TrianglesCount; l++)
                //    {
                //        float dist = 0;
                //        dist += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position);
                //        dist += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position);
                //        dist += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position);

                //        float dist1 = 0;
                //        dist1 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position);
                //        dist1 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position);
                //        dist1 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position);

                //        float dist2 = 0;
                //        dist2 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex0].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex2].Target.Position);
                //        dist2 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex1].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex0].Target.Position);
                //        dist2 += Vector3.DistanceSquared(m_highVertices[restHighTriangles[i].VertexIndex2].Position, m_lowVertices[lowResMesh.Triangles[l].VertexIndex1].Target.Position);

                //        int sw = 0;

                //        if (dist1 < dist && dist1 < dist2)
                //        {
                //            dist = dist1;
                //            sw = 1;
                //        }

                //        if (dist2 < dist && dist2 < dist1)
                //        {
                //            dist = dist2;
                //            sw = 2;
                //        }

                //        if (dist < triDist)
                //        {
                //            triDist = dist;
                //            bestT = l;
                //            swtch = sw;
                //        }
                //    }


                //    //bestT = i % lowResMesh.TrianglesCount;
                //    //bestT = MyUtils.GetRandomInt(lowResMesh.TrianglesCount);

                //    int vi0 = lowResMesh.Triangles[bestT].VertexIndex0;
                //    int vi1 = lowResMesh.Triangles[bestT].VertexIndex1;
                //    int vi2 = lowResMesh.Triangles[bestT].VertexIndex2;

                //    if (swtch == 1)
                //    {
                //        vi0 = lowResMesh.Triangles[bestT].VertexIndex1;
                //        vi1 = lowResMesh.Triangles[bestT].VertexIndex2;
                //        vi2 = lowResMesh.Triangles[bestT].VertexIndex0;
                //    }

                //    if (swtch == 2)
                //    {
                //        vi0 = lowResMesh.Triangles[bestT].VertexIndex2;
                //        vi1 = lowResMesh.Triangles[bestT].VertexIndex0;
                //        vi2 = lowResMesh.Triangles[bestT].VertexIndex1;
                //    }

                //    var v0 = m_highVertices[restHighTriangles[i].VertexIndex0];
                //    v0.PositionMorph = m_lowVertices[vi0].Target.Position;
                //    v0.NormalMorph = m_lowVertices[vi0].Target.Normal;
                //    v0.AmbientMorph = m_lowVertices[vi0].Target.Ambient;
                //    m_highVertices[restHighTriangles[i].VertexIndex0] = v0;

                //    var v1 = m_highVertices[restHighTriangles[i].VertexIndex1];
                //    v1.PositionMorph = m_lowVertices[vi1].Target.Position;
                //    v1.NormalMorph = m_lowVertices[vi1].Target.Normal;
                //    v1.AmbientMorph = m_lowVertices[vi1].Target.Ambient;
                //    m_highVertices[restHighTriangles[i].VertexIndex1] = v1;

                //    var v2 = m_highVertices[restHighTriangles[i].VertexIndex2];
                //    v2.PositionMorph = m_lowVertices[vi2].Target.Position;
                //    v2.NormalMorph = m_lowVertices[vi2].Target.Normal;
                //    v2.AmbientMorph = m_lowVertices[vi2].Target.Ambient;
                //    m_highVertices[restHighTriangles[i].VertexIndex2] = v2;

                //}

                ////add low lod
                //for (int i = 0; i < lowResMesh.TrianglesCount; i++)
                //{
                //    var lt = lowResMesh.Triangles[i];

                //    m_highTriangles.Add(new MyVoxelTriangle()
                //    {
                //        VertexIndex0 = (ushort)(lt.VertexIndex0 + m_highVertices.Count),
                //        VertexIndex1 = (ushort)(lt.VertexIndex1 + m_highVertices.Count),
                //        VertexIndex2 = (ushort)(lt.VertexIndex2 + m_highVertices.Count),
                //    }
                //    );
                //}

                //for (int i = 0; i < m_lowVertices.Count; i++)
                //{
                //    var vertex = new MyVoxelVertex();
                //    vertex.Position = m_lowVertices[i].Target.Position;
                //    vertex.Normal = m_lowVertices[i].Target.Normal;
                //    vertex.Material = m_lowVertices[i].Target.Material;
                //    vertex.Ambient = 0;
                //    vertex.PositionMorph = vertex.Position;
                //    vertex.NormalMorph = vertex.Normal;
                //    vertex.MaterialMorph = vertex.Material;
                //    vertex.AmbientMorph = vertex.Ambient;
                //    m_highVertices.Add(vertex);
                //}
                

            //    List<MyVoxelTriangle> newTriangles = new List<MyVoxelTriangle>();

            //    for (int i = 0; i < m_highTriangles.Count; i++)
            //    {
            //        MyVoxelVertex v0 = m_highVertices[m_highTriangles[i].VertexIndex0];
            //        MyVoxelVertex v1 = m_highVertices[m_highTriangles[i].VertexIndex1];
            //        MyVoxelVertex v2 = m_highVertices[m_highTriangles[i].VertexIndex2];

            //        for (int v = 0; v < m_highVertices.Count; v++)
            //        {
            //            if (v0.Position == m_highVertices[v].Position)
            //            {
            //                if (v0.PositionMorph == m_highVertices[v].PositionMorph)
            //                {
            //                    var t = m_highTriangles[i];
            //                    t.VertexIndex0 = (ushort)v;
            //                    m_highTriangles[i] = t;
            //                    break;
            //                }
            //                else
            //                {
            //                    var vert1 = m_highVertices[m_highTriangles[i].VertexIndex1];
            //                    var vert2 = m_highVertices[m_highTriangles[i].VertexIndex2];

            //                    vert1.Position = m_highVertices[v].Position;
            //                    vert2.Position = m_highVertices[v].Position;

            //                    m_highVertices.Add(vert1);
            //                    m_highVertices.Add(vert2);

            //                    newTriangles.Add(new MyVoxelTriangle()
            //                    {
            //                        VertexIndex0 = (ushort)v,
            //                        VertexIndex1 = (ushort)(m_highVertices.Count - 2),
            //                        VertexIndex2 = (ushort)(m_highVertices.Count - 1)
            //                    });
            //                }
            //            }
            //        }

            //        for (int v = 0; v < m_highVertices.Count; v++)
            //        {
            //            if (v1.Position == m_highVertices[v].Position)
            //            {
            //                if (v1.PositionMorph == m_highVertices[v].PositionMorph)
            //                {
            //                    var t = m_highTriangles[i];
            //                    t.VertexIndex1 = (ushort)v;
            //                    m_highTriangles[i] = t;
            //                    break;
            //                }
            //                else
            //                {
            //                    var vert0 = m_highVertices[m_highTriangles[i].VertexIndex0];
            //                    var vert2 = m_highVertices[m_highTriangles[i].VertexIndex2];

            //                    vert0.Position = m_highVertices[v].Position;
            //                    vert2.Position = m_highVertices[v].Position;

            //                    m_highVertices.Add(vert0);
            //                    m_highVertices.Add(vert2);

            //                    newTriangles.Add(new MyVoxelTriangle()
            //                    {
            //                        VertexIndex0 = (ushort)(m_highVertices.Count - 2),
            //                        VertexIndex1 = (ushort)v,
            //                        VertexIndex2 = (ushort)(m_highVertices.Count - 1)
            //                    });
            //                }
                      
            //            }
            //        }

            //        for (int v = 0; v < m_highVertices.Count; v++)
            //        {
            //            if (v2.Position == m_highVertices[v].Position)
            //            {
            //                if (v2.PositionMorph == m_highVertices[v].PositionMorph)
            //                {
            //                    var t = m_highTriangles[i];
            //                    t.VertexIndex2 = (ushort)v;
            //                    m_highTriangles[i] = t;
            //                    break;
            //                }
            //                else
            //                {
            //                    var vert0 = m_highVertices[m_highTriangles[i].VertexIndex0];
            //                    var vert1 = m_highVertices[m_highTriangles[i].VertexIndex1];

            //                    vert0.Position = m_highVertices[v].Position;
            //                    vert1.Position = m_highVertices[v].Position;

            //                    m_highVertices.Add(vert0);
            //                    m_highVertices.Add(vert1);

            //                    newTriangles.Add(new MyVoxelTriangle()
            //                    {
            //                        VertexIndex0 = (ushort)(m_highVertices.Count - 2),
            //                        VertexIndex1 = (ushort)(m_highVertices.Count - 1),
            //                        VertexIndex2 = (ushort)v
            //                    });
            //                }
                         
            //            }
            //        }
            //    }


            //    foreach (var t in newTriangles)
            //    {
            //        m_highTriangles.Add(t);
            //    }


                float largestDistance = float.MinValue;
                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    MyVoxelVertex vertex = m_highVertices[i];
                    float p1 = vertex.Position.AbsMax();
                    if (p1 > largestDistance)
                        largestDistance = p1;
                    float p2 = vertex.PositionMorph.AbsMax();
                    if (p2 > largestDistance)
                        largestDistance = p2;
                }


                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    MyVoxelVertex vertex = m_highVertices[i];

                    vertex.Position /= largestDistance;
                    vertex.PositionMorph /= largestDistance;

                    m_highVertices[i] = vertex;

                }

                meta.PositionScale *= largestDistance;
            }
            else
            {
            }

         

            for (int i = 0; i < m_highVertices.Count; i++)
            {
                MyVoxelVertex vertex = m_highVertices[i];

                meta.LocalAabb.Include(vertex.Position * meta.PositionScale + meta.PositionOffset);
                meta.LocalAabb.Include(vertex.PositionMorph * meta.PositionScale + meta.PositionOffset);

                Debug.Assert(vertex.Position.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
                Debug.Assert(vertex.PositionMorph.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
            }
            

            for (int i = 0; i < m_highTriangles.Count; i++)
            {
                MyVoxelTriangle srcTriangle = m_highTriangles[i];
                MyVoxelVertex vertex0, vertex1, vertex2;
                vertex0 = m_highVertices[srcTriangle.VertexIndex0];
                vertex1 = m_highVertices[srcTriangle.VertexIndex1];
                vertex2 = m_highVertices[srcTriangle.VertexIndex2];
                
                if (vertex0.Material == vertex1.Material &&
                    vertex0.Material == vertex2.Material &&
                    vertex0.Material == vertex0.MaterialMorph &&
                    vertex0.Material == vertex1.MaterialMorph &&
                    vertex0.Material == vertex2.MaterialMorph)
                { // single material
                    var matIdx = vertex0.Material;

                    //  This is single-texture triangleVertexes, so we can choose material from any edge
                    SingleMaterialHelper materialHelper;
                    if (!SM_Helpers.TryGetValue(matIdx, out materialHelper))
                    {
                        if (!SM_HelperPool.TryDequeue(out materialHelper))
                            materialHelper = new SingleMaterialHelper();
                        materialHelper.Material = matIdx;
                        SM_Helpers.Add(matIdx, materialHelper);
                    }

                    VertexInBatchLookup batchLookup;
                    if (!SM_BatchLookups.TryGetValue(matIdx, out batchLookup))
                    {
                        if (!SM_BatchLookupPool.TryDequeue(out batchLookup))
                            batchLookup = new VertexInBatchLookup();
                        SM_BatchLookups.Add(matIdx, batchLookup);
                    }

                    AddVertexToBuffer(materialHelper, ref vertex0, batchLookup, srcTriangle.VertexIndex0);
                    AddVertexToBuffer(materialHelper, ref vertex1, batchLookup, srcTriangle.VertexIndex1);
                    AddVertexToBuffer(materialHelper, ref vertex2, batchLookup, srcTriangle.VertexIndex2);

                    //  Add indices
                    int nextTriangleIndex = materialHelper.IndexCount;
                    materialHelper.Indices[nextTriangleIndex + 0] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex0);
                    materialHelper.Indices[nextTriangleIndex + 1] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex1);
                    materialHelper.Indices[nextTriangleIndex + 2] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex2);
                    materialHelper.IndexCount += 3;

                    if ((materialHelper.VertexCount >= MAX_VERTICES_COUNT_STOP) ||
                        (materialHelper.IndexCount >= MAX_INDICES_COUNT_STOP))
                    {
                        //  If this batch is almost full (or is full), we end it and start with new one
                        EndSingleMaterial(materialHelper, outBatches);
                    }
                }
                else
                {
                    Vector3I materials = GetMaterials(ref vertex0, ref vertex1, ref vertex2);
                    var voxelMaterialCount = MyDefinitionManager.Static.VoxelMaterialCount;
                    int id = materials.X + voxelMaterialCount * (materials.Y + materials.Z * voxelMaterialCount);

                    // Assign current material
                    MultiMaterialHelper helper = null;
                    if (!MM_Helpers.TryGetValue(id, out helper))
                    {
                        if (!MM_HelperPool.TryDequeue(out helper))
                            helper = new MultiMaterialHelper();
                        helper.Material0 = materials.X;
                        helper.Material1 = materials.Y;
                        helper.Material2 = materials.Z;
                        MM_Helpers.Add(id, helper);
                    }

                    helper.AddVertex(ref vertex0);
                    helper.AddVertex(ref vertex1);
                    helper.AddVertex(ref vertex2);

                    if (helper.Vertices.Count >= MAX_VERTICES_COUNT_STOP)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                }
            }

            { //renderCell.End();
                foreach (var helper in SM_Helpers.Values)
                {
                    Debug.Assert(helper != null);
                    if (helper.IndexCount > 0)
                    {
                        EndSingleMaterial(helper, outBatches);
                    }
                    helper.IndexCount = 0;
                    helper.VertexCount = 0;
                    SM_HelperPool.Enqueue(helper);
                }
                SM_Helpers.Clear();

                foreach (var helper in MM_Helpers.Values)
                {
                    if (helper.Vertices.Count > 0)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                    helper.Vertices.Clear();
                    MM_HelperPool.Enqueue(helper);
                }
                MM_Helpers.Clear();

                foreach (var lookup in SM_BatchLookups.Values)
                {
                    SM_BatchLookupPool.Enqueue(lookup);
                }
                SM_BatchLookups.Clear();
            }

            m_morphMap.Clear();
        }
        private void ProcessVertex(MyIsoMesh mesh, int vertexIndex, ref BoundingBox localAabb, ref Vector3 positionScale, ref Vector3D positionOffset, out MyVoxelVertex vertex)
        {
            vertex.Position = mesh.Positions[vertexIndex];
            vertex.Normal = mesh.Normals[vertexIndex];
            vertex.Material = mesh.Materials[vertexIndex];
            vertex.Ambient = 0f;
            Vertex morph;
            if (m_morphMap.TryGetValue(mesh.Cells[vertexIndex] >> 1, out morph))
            {
                vertex.PositionMorph = morph.Target.Position;
                vertex.NormalMorph = morph.Target.Normal;
                vertex.MaterialMorph = morph.Target.Material;
            }
            else
            {
                vertex.PositionMorph = vertex.Position;
                vertex.NormalMorph = vertex.Normal;
                vertex.MaterialMorph = vertex.Material;
            }
            localAabb.Include(vertex.Position * positionScale + positionOffset);
            localAabb.Include(vertex.PositionMorph * positionScale + positionOffset);

            Debug.Assert(vertex.Position.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
            Debug.Assert(vertex.PositionMorph.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
        }
        internal void BuildCell(
            MyPrecalcJobRender.Args args,
            MyIsoMesh highResMesh,
            MyIsoMesh lowResMesh,
            List <MyClipmapCellBatch> outBatches,
            out Vector3D positionOffset,
            out Vector3 positionScale,
            out BoundingBox localBoundingBox)
        {
            Debug.Assert(highResMesh != null);

            {
                positionOffset = highResMesh.PositionOffset;
                positionScale  = highResMesh.PositionScale;
            }

            {
                // Find low resolution LoD vertices to map to
                float vertexCellSizeInParentLod = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << (args.Cell.Lod + 1));
                float collisionThreshold        = 0.0001f * vertexCellSizeInParentLod * vertexCellSizeInParentLod;
                if (lowResMesh != null)
                {
                    /*
                     * Derived transformation of normalized coordinates from low res mesh to high res mesh.
                     * _l is for low res, _h for high res, x is vertex position
                     * x = x_l * scale_l + offset_l
                     * x_h = (x - offset_h) / scale_h
                     * x_h = ((x_l * scale_l + offset_l) - offset_h) / scale_h
                     * x_h = (x_l * scale_l + offset_l - offset_h) / scale_h
                     * x_h = x_l * (scale_l / scale_h) + ((offset_l - offset_h) / scale_h)
                     */
                    Vector3 morphOffset, morphScale;
                    morphScale  = lowResMesh.PositionScale / highResMesh.PositionScale;
                    morphOffset = (Vector3)(lowResMesh.PositionOffset - highResMesh.PositionOffset) / highResMesh.PositionScale;
                    for (int i = 0; i < lowResMesh.VerticesCount; ++i)
                    {
                        var vertex = new Vertex
                        {
                            Target = new MorphData {
                                Position = lowResMesh.Positions[i] * morphScale + morphOffset,
                                Normal   = lowResMesh.Normals[i],
                                Material = lowResMesh.Materials[i],
                            },
                            Cell = lowResMesh.Cells[i],
                        };

                        if (m_morphMap.ContainsKey(vertex.Cell))
                        {
                            var collidedVertex = m_morphMap[vertex.Cell];
                            Debug.Assert(collidedVertex.Cell == vertex.Cell);

                            var collisionDist2 = (collidedVertex.Target.Position - vertex.Target.Position).LengthSquared();
                            if (collisionDist2 > collisionThreshold)
                            {
                                //Debug.Fail(string.Format("Collision between vertices! {0} > {1}", collisionDist2, collisionThreshold));
                                m_collisionList.Add(collidedVertex);
                            }
                        }
                        m_morphMap[vertex.Cell] = vertex;
                    }
                }

#if false
                ProcessMorphTargetCollisions(args, vertexCellSizeInParentLod);
#endif

#if false
                EnsureMorphTargetExists(args, highResMesh);
#endif
            }

            localBoundingBox = BoundingBox.CreateInvalid();

            //  Increase lookup count, so we will think that all vertices in helper arrays are new
            foreach (var lookup in SM_BatchLookups.Values)
            {
                lookup.ResetBatch();
            }

            for (int i = 0; i < highResMesh.Triangles.Count; i++)
            {
                MyVoxelTriangle srcTriangle = highResMesh.Triangles[i];
                MyVoxelVertex   vertex0, vertex1, vertex2;
                ProcessVertex(highResMesh, srcTriangle.VertexIndex0, ref localBoundingBox, ref positionScale, ref positionOffset, out vertex0);
                ProcessVertex(highResMesh, srcTriangle.VertexIndex1, ref localBoundingBox, ref positionScale, ref positionOffset, out vertex1);
                ProcessVertex(highResMesh, srcTriangle.VertexIndex2, ref localBoundingBox, ref positionScale, ref positionOffset, out vertex2);

                if (MyPerGameSettings.ConstantVoxelAmbient.HasValue)
                {
                    vertex0.Ambient = vertex1.Ambient = vertex2.Ambient = MyPerGameSettings.ConstantVoxelAmbient.Value;
                }

                if (vertex0.Material == vertex1.Material &&
                    vertex0.Material == vertex2.Material &&
                    vertex0.Material == vertex0.MaterialMorph &&
                    vertex0.Material == vertex1.MaterialMorph &&
                    vertex0.Material == vertex2.MaterialMorph)
                { // single material
                    var matIdx = vertex0.Material;

                    //  This is single-texture triangleVertexes, so we can choose material from any edge
                    SingleMaterialHelper materialHelper;
                    if (!SM_Helpers.TryGetValue(matIdx, out materialHelper))
                    {
                        if (!SM_HelperPool.TryDequeue(out materialHelper))
                        {
                            materialHelper = new SingleMaterialHelper();
                        }
                        materialHelper.Material = matIdx;
                        SM_Helpers.Add(matIdx, materialHelper);
                    }

                    VertexInBatchLookup batchLookup;
                    if (!SM_BatchLookups.TryGetValue(matIdx, out batchLookup))
                    {
                        if (!SM_BatchLookupPool.TryDequeue(out batchLookup))
                        {
                            batchLookup = new VertexInBatchLookup();
                        }
                        SM_BatchLookups.Add(matIdx, batchLookup);
                    }

                    AddVertexToBuffer(materialHelper, ref vertex0, batchLookup, srcTriangle.VertexIndex0);
                    AddVertexToBuffer(materialHelper, ref vertex1, batchLookup, srcTriangle.VertexIndex1);
                    AddVertexToBuffer(materialHelper, ref vertex2, batchLookup, srcTriangle.VertexIndex2);

                    //  Add indices
                    int nextTriangleIndex = materialHelper.IndexCount;
                    materialHelper.Indices[nextTriangleIndex + 0] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex0);
                    materialHelper.Indices[nextTriangleIndex + 1] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex1);
                    materialHelper.Indices[nextTriangleIndex + 2] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex2);
                    materialHelper.IndexCount += 3;

                    if ((materialHelper.VertexCount >= MAX_VERTICES_COUNT_STOP) ||
                        (materialHelper.IndexCount >= MAX_INDICES_COUNT_STOP))
                    {
                        //  If this batch is almost full (or is full), we end it and start with new one
                        EndSingleMaterial(materialHelper, outBatches);
                    }
                }
                else
                {
                    Vector3I materials          = GetMaterials(ref vertex0, ref vertex1, ref vertex2);
                    var      voxelMaterialCount = MyDefinitionManager.Static.VoxelMaterialCount;
                    int      id = materials.X + voxelMaterialCount * (materials.Y + materials.Z * voxelMaterialCount);

                    // Assign current material
                    MultiMaterialHelper helper = null;
                    if (!MM_Helpers.TryGetValue(id, out helper))
                    {
                        if (!MM_HelperPool.TryDequeue(out helper))
                        {
                            helper = new MultiMaterialHelper();
                        }
                        helper.Material0 = materials.X;
                        helper.Material1 = materials.Y;
                        helper.Material2 = materials.Z;
                        MM_Helpers.Add(id, helper);
                    }

                    helper.AddVertex(ref vertex0);
                    helper.AddVertex(ref vertex1);
                    helper.AddVertex(ref vertex2);

                    if (helper.Vertices.Count >= MAX_VERTICES_COUNT_STOP)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                }
            }

            { //renderCell.End();
                foreach (var helper in SM_Helpers.Values)
                {
                    Debug.Assert(helper != null);
                    if (helper.IndexCount > 0)
                    {
                        EndSingleMaterial(helper, outBatches);
                    }
                    helper.IndexCount  = 0;
                    helper.VertexCount = 0;
                    SM_HelperPool.Enqueue(helper);
                }
                SM_Helpers.Clear();

                foreach (var helper in MM_Helpers.Values)
                {
                    if (helper.Vertices.Count > 0)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                    helper.Vertices.Clear();
                    MM_HelperPool.Enqueue(helper);
                }
                MM_Helpers.Clear();

                foreach (var lookup in SM_BatchLookups.Values)
                {
                    SM_BatchLookupPool.Enqueue(lookup);
                }
                SM_BatchLookups.Clear();
            }

            m_morphMap.Clear();
        }
Exemple #28
0
        public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient)
        {
            // change range so normal can be computed at edges (expand by 1 in all directions)
            voxelStart -= 1;
            voxelEnd   += 1;
            m_cache.Resize(voxelStart, voxelEnd);
            storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd);
            if (!m_cache.ContainsIsoSurface())
            {
                return(null);
            }

            var    center           = (storage.Size / 2) * MyVoxelConstants.VOXEL_SIZE_IN_METRES;
            var    voxelSize        = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod);
            var    vertexCellOffset = voxelStart - AffectedRangeOffset;
            double numCellsHalf     = 0.5 * (m_cache.Size3D.X - 3);
            var    posOffset        = ((Vector3D)vertexCellOffset + numCellsHalf) * (double)voxelSize;

            if (generateMaterials)
            {
                m_cache.ClearMaterials(0);
            }

            IsoMesher mesher = new IsoMesher();

            ProfilerShort.Begin("Dual Contouring");
            unsafe
            {
                fixed(byte *voxels = m_cache.Data)
                {
                    var size3d = m_cache.Size3D;

                    Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z);
                    mesher.Calculate(size3d.X, (VoxelData *)voxels, m_buffer, useAmbient, posOffset - center);
                }
            }
            ProfilerShort.End();

            if (generateMaterials)
            {
                using (MyVoxelMaterialRequestHelper.StartContouring())
                {
                    storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, lod, ref voxelStart, ref voxelEnd);
                    bool hasOcclusionHint = false;
                    FixCacheMaterial(voxelStart, voxelEnd);
                    unsafe
                    {
                        fixed(byte *voxels = m_cache.Data)
                        {
                            var size3d = m_cache.Size3D;

                            Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z);
                            mesher.CalculateMaterials(size3d.X, (VoxelData *)voxels, hasOcclusionHint);
                        }
                    }
                }
            }
            else
            {
                m_cache.ClearMaterials(0);
            }

            mesher.Finish(m_buffer);

            if (m_buffer.VerticesCount == 0 && m_buffer.Triangles.Count == 0)
            {
                return(null);
            }

            ProfilerShort.Begin("Geometry post-processing");
            {
                var positions   = m_buffer.Positions.GetInternalArray();
                var vertexCells = m_buffer.Cells.GetInternalArray();
                for (int i = 0; i < m_buffer.VerticesCount; i++)
                {
                    Debug.Assert(positions[i].IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
                    vertexCells[i] += vertexCellOffset;
                    Debug.Assert(vertexCells[i].IsInsideInclusive(voxelStart + 1, voxelEnd - 1));
                }

                m_buffer.PositionOffset = posOffset;
                m_buffer.PositionScale  = new Vector3((float)(numCellsHalf * voxelSize));
                m_buffer.CellStart      = voxelStart + 1;
                m_buffer.CellEnd        = voxelEnd - 1;
            }
            ProfilerShort.End();

            // Replace filled mesh with new one.
            // This way prevents allocation of meshes which then end up empty.
            var buffer = m_buffer;

            m_buffer = new MyIsoMesh();
            return(buffer);
        }
        internal void BuildCell(
            MyPrecalcJobRender.Args args,
            MyIsoMesh highResMesh,
            MyIsoMesh lowResMesh,
            List<MyClipmapCellBatch> outBatches,
            out MyClipmapCellMeshMetadata meta)
        {
            ProfilerShort.Begin("MyRenderCellBuilder.BuildCell");
            Debug.Assert(highResMesh != null);

            meta.Cell = args.Cell;
            meta.PositionOffset = highResMesh.PositionOffset;
            meta.PositionScale = highResMesh.PositionScale;
            meta.LocalAabb = BoundingBox.CreateInvalid();

            m_lowVertices.SetSize(0);
            m_highVertices.SetSize(0);

            ProcessLowMesh(highResMesh, lowResMesh);

            //  Increase lookup count, so we will think that all vertices in helper arrays are new
            foreach (var lookup in SM_BatchLookups.Values)
            {
                lookup.ResetBatch();
            }

    
            for (int i = 0; i < highResMesh.VerticesCount; i++)
            {
                MyVoxelVertex vertex;
                ProcessHighVertex(highResMesh, i, out vertex);
            }

            if (lowResMesh != null)
            {
                m_highGrid.ClearFast();

                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    Vector3 position = m_highVertices[i].Position;
                    m_highGrid.AddPoint(ref position, i);
                }

                //TODO: Fix ocassional bad triangles on asteroid
                /*
                //Closest vertex
                for (int l = 0; l < m_lowVertices.Count; l++)
                {
                    Vector3 targetPosition = m_lowVertices[l].Target.Position;

                    int bestV = -1;
                    float ldist = float.MaxValue;
                    float startMeters = 1;
                    float maxDistance = 10;

                    MyVector3Grid<int>.Enumerator points = default(MyVector3Grid<int>.Enumerator);
                    while (startMeters < maxDistance)
                    {
                        points = m_highGrid.GetPointsCloserThan(ref targetPosition, startMeters);

                        while (points.MoveNext())
                        {
                            var dist = Vector3.DistanceSquared(targetPosition, m_highVertices[points.Current].Position);
                            if (dist < ldist)
                            {
                                ldist = dist;
                                bestV = points.Current;
                            }
                        }

                        if (bestV != -1)
                            break;

                        startMeters += 1;
                    }

                    if (bestV != -1)
                    {
                        var vtx = m_highVertices[bestV];
                        vtx.PositionMorph = m_lowVertices[l].Target.Position;
                        vtx.NormalMorph = m_lowVertices[l].Target.Normal;
                        vtx.MaterialMorph = m_lowVertices[l].Target.Material;
                        vtx.AmbientMorph = m_lowVertices[l].Target.Ambient;
                        m_highVertices[bestV] = vtx;
                    }
                    else
                    {
                    }
                }

                */

                //Closest vertex
                float largestDistance = float.MinValue;
                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    float ldist = float.MaxValue;
                    int bestV = -1;

                    for (int l = 0; l < m_lowVertices.Count; l++)
                    {
                        var dist = Vector3.DistanceSquared(m_lowVertices[l].Target.Position, m_highVertices[i].Position);
                        if (dist < ldist)
                        {
                            ldist = dist;
                            bestV = l;
                        }
                    }

                    var highVertex = m_highVertices[i];
                    highVertex.PositionMorph = m_lowVertices[bestV].Target.Position;
                    highVertex.NormalMorph = m_lowVertices[bestV].Target.Normal;
                    highVertex.MaterialMorph = m_lowVertices[bestV].Target.Material;
                    highVertex.AmbientMorph = m_lowVertices[bestV].Target.Ambient;

                    float p1 = highVertex.Position.AbsMax();
                    if (p1 > largestDistance)
                        largestDistance = p1;
                    float p2 = highVertex.PositionMorph.AbsMax();
                    if (p2 > largestDistance)
                        largestDistance = p2;

                    m_highVertices[i] = highVertex;
                }

                for (int i = 0; i < m_highVertices.Count; i++)
                {
                    MyVoxelVertex vertex = m_highVertices[i];

                    vertex.Position /= largestDistance;
                    vertex.PositionMorph /= largestDistance;

                    m_highVertices[i] = vertex;
                }

                meta.PositionScale *= largestDistance;
            }
            
            //Create batches
            for (int i = 0; i < m_highVertices.Count; i++)
            {
                MyVoxelVertex vertex = m_highVertices[i];

                meta.LocalAabb.Include(vertex.Position * meta.PositionScale + meta.PositionOffset);
                meta.LocalAabb.Include(vertex.PositionMorph * meta.PositionScale + meta.PositionOffset);

                Debug.Assert(vertex.Position.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
                Debug.Assert(vertex.PositionMorph.IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
            }

            for (int i = 0; i < highResMesh.TrianglesCount; i++)
            {
                MyVoxelTriangle srcTriangle = highResMesh.Triangles[i];
                MyVoxelVertex vertex0 = m_highVertices[srcTriangle.VertexIndex0];
                MyVoxelVertex vertex1 = m_highVertices[srcTriangle.VertexIndex1];
                MyVoxelVertex vertex2 = m_highVertices[srcTriangle.VertexIndex2];
                
                if (vertex0.Material == vertex1.Material &&
                    vertex0.Material == vertex2.Material &&
                    vertex0.Material == vertex0.MaterialMorph &&
                    vertex0.Material == vertex1.MaterialMorph &&
                    vertex0.Material == vertex2.MaterialMorph)
                { // single material
                    var matIdx = vertex0.Material;

                    //  This is single-texture triangleVertexes, so we can choose material from any edge
                    SingleMaterialHelper materialHelper;
                    if (!SM_Helpers.TryGetValue(matIdx, out materialHelper))
                    {
                        if (!SM_HelperPool.TryDequeue(out materialHelper))
                            materialHelper = new SingleMaterialHelper();
                        materialHelper.Material = matIdx;
                        SM_Helpers.Add(matIdx, materialHelper);
                    }

                    VertexInBatchLookup batchLookup;
                    if (!SM_BatchLookups.TryGetValue(matIdx, out batchLookup))
                    {
                        if (!SM_BatchLookupPool.TryDequeue(out batchLookup))
                            batchLookup = new VertexInBatchLookup();
                        SM_BatchLookups.Add(matIdx, batchLookup);
                    }

                    AddVertexToBuffer(materialHelper, ref vertex0, batchLookup, srcTriangle.VertexIndex0);
                    AddVertexToBuffer(materialHelper, ref vertex1, batchLookup, srcTriangle.VertexIndex1);
                    AddVertexToBuffer(materialHelper, ref vertex2, batchLookup, srcTriangle.VertexIndex2);

                    //  Add indices
                    int nextTriangleIndex = materialHelper.IndexCount;
                    materialHelper.Indices[nextTriangleIndex + 0] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex0);
                    materialHelper.Indices[nextTriangleIndex + 1] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex1);
                    materialHelper.Indices[nextTriangleIndex + 2] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex2);
                    materialHelper.IndexCount += 3;

                    if ((materialHelper.VertexCount >= MAX_VERTICES_COUNT_STOP) ||
                        (materialHelper.IndexCount >= MAX_INDICES_COUNT_STOP))
                    {
                        //  If this batch is almost full (or is full), we end it and start with new one
                        EndSingleMaterial(materialHelper, outBatches);
                    }
                }
                else
                {
                    Vector3I materials = GetMaterials(ref vertex0, ref vertex1, ref vertex2);
                    Debug.Assert(materials.X < 1 << 10, "Too many materials");
                    Debug.Assert(materials.Y < 1 << 10, "Too many materials");
                    Debug.Assert(materials.Z < 1 << 10, "Too many materials");
                    int id = materials.X + (materials.Y + (materials.Z << 10) << 10);

                    // Assign current material
                    MultiMaterialHelper helper = null;
                    if (!MM_Helpers.TryGetValue(id, out helper))
                    {
                        if (!MM_HelperPool.TryDequeue(out helper))
                            helper = new MultiMaterialHelper();
                        helper.Material0 = materials.X;
                        helper.Material1 = materials.Y;
                        helper.Material2 = materials.Z;
                        MM_Helpers.Add(id, helper);
                    }

                    helper.AddVertex(ref vertex0);
                    helper.AddVertex(ref vertex1);
                    helper.AddVertex(ref vertex2);

                    if (helper.Vertices.Count >= MAX_VERTICES_COUNT_STOP)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                }
            }

            { //renderCell.End();
                foreach (var helper in SM_Helpers.Values)
                {
                    Debug.Assert(helper != null);
                    if (helper.IndexCount > 0)
                    {
                        EndSingleMaterial(helper, outBatches);
                    }
                    helper.IndexCount = 0;
                    helper.VertexCount = 0;
                    SM_HelperPool.Enqueue(helper);
                }
                SM_Helpers.Clear();

                foreach (var helper in MM_Helpers.Values)
                {
                    if (helper.Vertices.Count > 0)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                    helper.Vertices.Clear();
                    MM_HelperPool.Enqueue(helper);
                }
                MM_Helpers.Clear();

                foreach (var lookup in SM_BatchLookups.Values)
                {
                    SM_BatchLookupPool.Enqueue(lookup);
                }
                SM_BatchLookups.Clear();
            }

            m_morphMap.Clear();
            meta.BatchCount = outBatches.Count;
            ProfilerShort.End();
        }
 private void ProcessHighVertex(MyIsoMesh mesh, int vertexIndex, out MyVoxelVertex vertex)
 {
     vertex = new MyVoxelVertex();
     vertex.Position = mesh.Positions[vertexIndex];
     vertex.Normal = mesh.Normals[vertexIndex];
     vertex.Material = mesh.Materials[vertexIndex];
     vertex.Ambient = mesh.Ambient[vertexIndex];
     vertex.Cell = mesh.Cells[vertexIndex];
     vertex.PositionMorph = vertex.Position;
     vertex.NormalMorph = vertex.Normal;
     vertex.MaterialMorph = vertex.Material;
     vertex.AmbientMorph = vertex.Ambient;
     
     m_highVertices.Add(vertex);
 }
        private void ProcessLowMesh(MyIsoMesh highResMesh, MyIsoMesh lowResMesh)
        {
            ProfilerShort.Begin("ProcessLowMesh");
            if (lowResMesh != null)
            {
                /*
                 * Derived transformation of normalized coordinates from low res mesh to high res mesh.
                 * _l is for low res, _h for high res, x is vertex position
                 x = x_l * scale_l + offset_l
                 x_h = (x - offset_h) / scale_h
                 x_h = ((x_l * scale_l + offset_l) - offset_h) / scale_h
                 x_h = (x_l * scale_l + offset_l - offset_h) / scale_h
                 x_h = x_l * (scale_l / scale_h) + ((offset_l - offset_h) / scale_h)
                 */
                Vector3 morphOffset, morphScale;
                morphScale = lowResMesh.PositionScale / highResMesh.PositionScale;
                morphOffset = (Vector3)(lowResMesh.PositionOffset - highResMesh.PositionOffset) / highResMesh.PositionScale;
                for (int i = 0; i < lowResMesh.VerticesCount; ++i)
                {
                    var vertex = new Vertex
                    {
                        Target = new MorphData
                        {
                            Position = lowResMesh.Positions[i] * morphScale + morphOffset,
                            Normal = lowResMesh.Normals[i],
                            Material = lowResMesh.Materials[i],
                            Ambient = lowResMesh.Ambient[i],
                        },
                        Cell = lowResMesh.Cells[i],
                    };

                    m_lowVertices.Add(vertex);
                    m_morphMap[vertex.Cell] = vertex;
                }
            }
            ProfilerShort.End();
        }
Exemple #32
0
        public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient, bool doNotCheck = false)
        {
            // change range so normal can be computed at edges (expand by 1 in all directions)
            voxelStart -= 1;
            voxelEnd   += 1;

            if (storage == null)
            {
                return(null);
            }

            using (storage.Pin())
            {
                if (storage.Closed)
                {
                    return(null);
                }

                MyVoxelRequestFlags request = MyVoxelRequestFlags.ContentChecked; // | (doNotCheck ? MyVoxelRequestFlags.DoNotCheck : 0);
                //if (lod == 0 && generateMaterials) request |= MyVoxelRequestFlags.AdviseCache;

                bool readAmbient = false;

                if (generateMaterials && storage.DataProvider != null && storage.DataProvider.ProvidesAmbient)
                {
                    readAmbient = true;
                }

                m_cache.Resize(voxelStart, voxelEnd);
                if (readAmbient)
                {
                    m_cache.StoreOcclusion = true;
                }

                storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd, ref request);

                if (request.HasFlag(MyVoxelRequestFlags.EmptyContent) || request.HasFlag(MyVoxelRequestFlags.FullContent) ||
                    (!request.HasFlag(MyVoxelRequestFlags.ContentChecked) && !m_cache.ContainsIsoSurface()))
                {
                    //if(generateMaterials && lod == 0) Debugger.Break();
                    //storage.DebugDrawChunk(voxelStart, voxelEnd);
                    return(null);
                }

                var    center           = (storage.Size / 2) * MyVoxelConstants.VOXEL_SIZE_IN_METRES;
                var    voxelSize        = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod);
                var    vertexCellOffset = voxelStart - AffectedRangeOffset;
                double numCellsHalf     = 0.5 * (m_cache.Size3D.X - 3);
                var    posOffset        = ((Vector3D)vertexCellOffset + numCellsHalf) * (double)voxelSize;

                if (generateMaterials)
                {
                    // 255 is the new black
                    m_cache.ClearMaterials(255);
                }

                if (readAmbient)
                {
                    m_cache.Clear(MyStorageDataTypeEnum.Occlusion, 0);
                }

                IsoMesher mesher = new IsoMesher();
                ProfilerShort.Begin("Dual Contouring");
                unsafe
                {
                    fixed(byte *content = m_cache[MyStorageDataTypeEnum.Content])
                    fixed(byte *material = m_cache[MyStorageDataTypeEnum.Material])
                    {
                        var size3d = m_cache.Size3D;

                        Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z);
                        mesher.Calculate(size3d.X, content, material, m_buffer, useAmbient, posOffset - center);
                    }
                }
                ProfilerShort.End();

                if (generateMaterials)
                {
                    request = 0;

                    request |= MyVoxelRequestFlags.SurfaceMaterial;
                    request |= MyVoxelRequestFlags.ConsiderContent;

                    var req = readAmbient ? MyStorageDataTypeFlags.Material | MyStorageDataTypeFlags.Occlusion : MyStorageDataTypeFlags.Material;

                    storage.ReadRange(m_cache, req, lod, ref voxelStart, ref voxelEnd, ref request);

                    FixCacheMaterial(voxelStart, voxelEnd);
                    unsafe
                    {
                        fixed(byte *content = m_cache[MyStorageDataTypeEnum.Content])
                        fixed(byte *material = m_cache[MyStorageDataTypeEnum.Material])
                        {
                            int materialOverride = request.HasFlag(MyVoxelRequestFlags.OneMaterial) ? m_cache.Material(0) : -1;
                            var size3d           = m_cache.Size3D;

                            Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z);

                            if (readAmbient)
                                fixed(byte *ambient = m_cache[MyStorageDataTypeEnum.Occlusion])
                                mesher.CalculateMaterials(size3d.X, content, material, ambient, materialOverride);
                            else
                            {
                                mesher.CalculateMaterials(size3d.X, content, material, null, materialOverride);
                            }
                        }
                    }
                }
                else
                {
                    m_cache.ClearMaterials(0);
                }

                mesher.Finish(m_buffer);

                if (m_buffer.VerticesCount == 0 || m_buffer.Triangles.Count == 0)
                {
                    return(null);
                }

                ProfilerShort.Begin("Geometry post-processing");
                {
                    var positions   = m_buffer.Positions.GetInternalArray();
                    var vertexCells = m_buffer.Cells.GetInternalArray();
                    var materials   = m_buffer.Materials.GetInternalArray();
                    for (int i = 0; i < m_buffer.VerticesCount; i++)
                    {
                        Debug.Assert(positions[i].IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
                        vertexCells[i] += vertexCellOffset;
                        Debug.Assert(vertexCells[i].IsInsideInclusive(voxelStart + 1, voxelEnd - 1));
                        Debug.Assert(materials[i] != MyVoxelConstants.NULL_MATERIAL);
                    }

                    m_buffer.PositionOffset = posOffset;
                    m_buffer.PositionScale  = new Vector3((float)(numCellsHalf * voxelSize));
                    m_buffer.CellStart      = voxelStart + 1;
                    m_buffer.CellEnd        = voxelEnd - 1;
                }
                ProfilerShort.End();

                // Replace filled mesh with new one.
                // This way prevents allocation of meshes which then end up empty.
                var buffer = m_buffer;
                m_buffer = new MyIsoMesh();
                return(buffer);
            }
        }
        public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient, bool doNotCheck, bool adviceCache = false)
        {

            m_resultVerticesCounter = 0;
            m_resultTrianglesCounter = 0;
            m_edgeVertexCalcCounter++;
            m_temporaryVoxelsCounter++;            

            CalcPolygCubeSize(lod, storage.Size);

            m_voxelStart = voxelStart;
            //voxelStart = voxelStart;
            //voxelEnd = voxelEnd;
            var ssize = storage.Size;
            m_cache.Resize(voxelStart, voxelEnd);

            // Load content first, check it if it contains isosurface, early exit if it doesn't.
            storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd);

            if (!m_cache.ContainsIsoSurface())
                return null;

            storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, lod, ref voxelStart, ref voxelEnd);

            ProfilerShort.Begin("Marching cubes");
            {
                //  Size of voxel or cell (in meters) and size of voxel map / voxel cells
                ComputeSizeAndOrigin(lod, storage.Size);


                var start = Vector3I.Zero;
                var end = voxelEnd - voxelStart - 3;
                Vector3I coord0 = start;


                for (var it = new Vector3I_RangeIterator(ref start, ref end); it.IsValid(); it.GetNext(out coord0))
                {
                    int cubeIndex = 0;
                    if (m_cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 1;
                    if (m_cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 2;
                    if (m_cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 4;
                    if (m_cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 8;
                    if (m_cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 16;
                    if (m_cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 32;
                    if (m_cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 64;
                    if (m_cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) cubeIndex |= 128;

                    //  Cube is entirely in/out of the surface
                    if (MyMarchingCubesConstants.EdgeTable[cubeIndex] == 0)
                    {
                        continue;
                    }

                    //  We can get this voxel content right from cache (not using GetVoxelContent method), because after CopyVoxelContents these array must be filled. But only content, not material, normal, etc.
                    Vector3I tempVoxelCoord0 = ComputeTemporaryVoxelData(m_cache, ref coord0, cubeIndex, lod);

                    //  Create the triangles
                    CreateTriangles(ref coord0, cubeIndex, ref tempVoxelCoord0);
                }
            }
            ProfilerShort.End();


            double numCellsHalf = 0.5f * (m_cache.Size3D.X);
            var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod);
            var vertexCellOffset = voxelStart - AffectedRangeOffset;

            IMyIsoMesherOutputBuffer isomesh = new MyIsoMesh();


            for (int i = 0; i < m_resultVerticesCounter; i++)
            {
                var pos = (m_resultVertices[i].Position - (Vector3)storage.Size / 2) / storage.Size;                
                m_resultVertices[i].Position = pos;
                m_resultVertices[i].PositionMorph = pos;
                m_resultVertices[i].NormalMorph = m_resultVertices[i].Normal;
                m_resultVertices[i].MaterialMorph = m_resultVertices[i].Material;
                m_resultVertices[i].AmbientMorph = m_resultVertices[i].Ambient;
            }

            for (int i = 0; i < m_resultVerticesCounter; i++)
            {
                isomesh.WriteVertex(ref m_resultVertices[i].Cell, ref m_resultVertices[i].Position, ref m_resultVertices[i].Normal, (byte)m_resultVertices[i].Material, m_resultVertices[i].Ambient);
            }

            for (int i = 0; i < m_resultTrianglesCounter; i++)
            {
                isomesh.WriteTriangle(m_resultTriangles[i].VertexIndex0, m_resultTriangles[i].VertexIndex1, m_resultTriangles[i].VertexIndex2);
            }

            var mIsoMesh = (MyIsoMesh)isomesh;
            mIsoMesh.PositionOffset = storage.Size / 2;
            mIsoMesh.PositionScale = storage.Size;
            mIsoMesh.CellStart = voxelStart;
            mIsoMesh.CellEnd = voxelEnd;

            var vertexCells = mIsoMesh.Cells.GetInternalArray();
            for (int i = 0; i < mIsoMesh.VerticesCount; i++)
            {
                vertexCells[i] += vertexCellOffset;
            }

            return (MyIsoMesh)isomesh;
        }
        private void EnsureMorphTargetExists(MyPrecalcJobRender.Args args, MyIsoMesh highResMesh)
        {
            // Ensure as many (ideally all) vertices have some mapping prepared.
            // This is here to resolve any missing parent only once for each vertex (main loop can visit vertices for each triangle they appear in).
            //var geometryData = highResMesh;
            for (int i = 0; i < highResMesh.VerticesCount; ++i)
            {
                Vector3 highResPosition = highResMesh.Positions[i];
                Vertex lowResVertex;

                Vector3I vertexCell = highResMesh.Cells[i] >> 1;
                if (!m_morphMap.TryGetValue(vertexCell, out lowResVertex))
                {
                    float scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << args.Cell.Lod);
                    Vector3 cell = highResPosition / scale;
                    cell *= 0.5f;
                    scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << (args.Cell.Lod + 1));
                    Vector3 lowResPosition = cell * scale;
                    var cellMin = vertexCell;
                    var cellMax = vertexCell + 1; // usually I need to find parent in this direction
                    float nearestDist = float.PositiveInfinity;
                    int nearestDistManhat = int.MaxValue;
                    Vector3I? nearestCell = null;
                    for (var it = new Vector3I.RangeIterator(ref cellMin, ref cellMax); it.IsValid(); it.MoveNext())
                    {
                        Vertex morph;
                        if (m_morphMap.TryGetValue(it.Current, out morph))
                        {
                            var tmp = it.Current - cellMin;
                            int distManhat = tmp.X + tmp.Y + tmp.Z;
                            float dist = (morph.Target.Position - lowResPosition).LengthSquared();
                            if (distManhat < nearestDistManhat ||
                                (distManhat == nearestDistManhat && dist < nearestDist))
                            {
                                nearestDist = dist;
                                nearestDistManhat = distManhat;
                                nearestCell = it.Current;
                            }
                        }
                    }

                    if (nearestCell.HasValue)
                    {
                        m_morphMap.Add(vertexCell, m_morphMap[nearestCell.Value]);
                    }
                    else
                    {
                        //Debug.Fail("I'm screwed");
                    }
                }
            }
        }
        public void SetMesh(MyCellCoord cell, MyIsoMesh mesh)
        {
            // Don't store anything but the most detailed lod (used in physics and raycasts).
            // This cache is mostly supposed to help physics and raycasts, not render.
            if (cell.Lod != 0)
                return;

            MyPrecalcComponent.AssertUpdateThread();
            using (m_lock.AcquireExclusiveUsing())
            {
                if (mesh != null)
                {
                    var key = cell.PackId64();
                    m_coordinateToMesh[key] = mesh;
                }
                else
                {
                    SetEmpty(ref cell, true);
                }
            }
        }
        public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient, bool doNotCheck = false)
        {
            // change range so normal can be computed at edges (expand by 1 in all directions)
            voxelStart -= 1;
            voxelEnd += 1;

            if (storage == null) return null;

            using (storage.Pin())
            {
                if (storage.Closed) return null;    

                MyVoxelRequestFlags request = MyVoxelRequestFlags.ContentChecked; // | (doNotCheck ? MyVoxelRequestFlags.DoNotCheck : 0);
                //if (lod == 0 && generateMaterials) request |= MyVoxelRequestFlags.AdviseCache;

                bool readAmbient = false;

                if (generateMaterials && storage.DataProvider != null && storage.DataProvider.ProvidesAmbient)
                    readAmbient = true;

                m_cache.Resize(voxelStart, voxelEnd);
                if (readAmbient) m_cache.StoreOcclusion = true;

                storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd, ref request);

                if (request.HasFlags(MyVoxelRequestFlags.EmptyContent) || request.HasFlags(MyVoxelRequestFlags.FullContent)
                    || (!request.HasFlags(MyVoxelRequestFlags.ContentChecked) && !m_cache.ContainsIsoSurface()))
                {
                    //if(generateMaterials && lod == 0) Debugger.Break();
                    //storage.DebugDrawChunk(voxelStart, voxelEnd);
                    return null;
                }

                var center = (storage.Size / 2) * MyVoxelConstants.VOXEL_SIZE_IN_METRES;
                var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod);
                var vertexCellOffset = voxelStart - AffectedRangeOffset;
                double numCellsHalf = 0.5 * (m_cache.Size3D.X - 3);
                var posOffset = ((Vector3D)vertexCellOffset + numCellsHalf) * (double)voxelSize;

                if (generateMaterials)
                {
                    // 255 is the new black
                    m_cache.ClearMaterials(255);
                }

                if (readAmbient)
                    m_cache.Clear(MyStorageDataTypeEnum.Occlusion, 0);

                IsoMesher mesher = new IsoMesher();
                ProfilerShort.Begin("Dual Contouring");
                unsafe
                {
                    fixed (byte* content = m_cache[MyStorageDataTypeEnum.Content])
                    fixed (byte* material = m_cache[MyStorageDataTypeEnum.Material])
                    {
                        var size3d = m_cache.Size3D;
                        Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z);
                        mesher.Calculate(size3d.X, content, material, m_buffer, useAmbient, posOffset - center);
                    }
                }
                
                if (generateMaterials)
                {
                    request = 0;

                    request |= MyVoxelRequestFlags.SurfaceMaterial;
                    request |= MyVoxelRequestFlags.ConsiderContent;

                    var req = readAmbient ? MyStorageDataTypeFlags.Material | MyStorageDataTypeFlags.Occlusion : MyStorageDataTypeFlags.Material;

                    storage.ReadRange(m_cache, req, lod, ref voxelStart, ref voxelEnd, ref request);

                    FixCacheMaterial(voxelStart, voxelEnd);
                    unsafe
                    {
                        fixed (byte* content = m_cache[MyStorageDataTypeEnum.Content])
                        fixed (byte* material = m_cache[MyStorageDataTypeEnum.Material])
                        {
                            int materialOverride = request.HasFlags(MyVoxelRequestFlags.OneMaterial) ? m_cache.Material(0) : -1;
                            var size3d = m_cache.Size3D;
                            Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z);

                            if (readAmbient)
                                fixed (byte* ambient = m_cache[MyStorageDataTypeEnum.Occlusion])
                                    mesher.CalculateMaterials(size3d.X, content, material, ambient, materialOverride);
                            else
                                mesher.CalculateMaterials(size3d.X, content, material, null, materialOverride);
                        }

                    }
                }
                else
                    m_cache.ClearMaterials(0);

                mesher.Finish(m_buffer);
                ProfilerShort.End();

                if (m_buffer.VerticesCount == 0 || m_buffer.Triangles.Count == 0)
                {
                    return null;
                }

                ProfilerShort.Begin("Geometry post-processing");
                {
                    var positions = m_buffer.Positions.GetInternalArray();
                    var vertexCells = m_buffer.Cells.GetInternalArray();
                    var materials = m_buffer.Materials.GetInternalArray();
                    var ambients = m_buffer.Ambient.GetInternalArray();
                    for (int i = 0; i < m_buffer.VerticesCount; i++)
                    {
                        Debug.Assert(positions[i].IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
                        vertexCells[i] += vertexCellOffset;
                        Debug.Assert(vertexCells[i].IsInsideInclusive(voxelStart + 1, voxelEnd - 1));
                        Debug.Assert(materials[i] != MyVoxelConstants.NULL_MATERIAL);
                        Debug.Assert(ambients[i] >= 0 && ambients[i] <= 1);
                    }

                    m_buffer.PositionOffset = posOffset;
                    m_buffer.PositionScale = new Vector3((float)(numCellsHalf * voxelSize));
                    m_buffer.CellStart = voxelStart + 1;
                    m_buffer.CellEnd = voxelEnd - 1;
                }
                ProfilerShort.End();

                // Replace filled mesh with new one.
                // This way prevents allocation of meshes which then end up empty.
                var buffer = m_buffer;
                m_buffer = new MyIsoMesh();
                return buffer;
            }
        }
        public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials)
        {
            // change range so normal can be computed at edges (expand by 1 in all directions)
            voxelStart -= 1;
            voxelEnd   += 1;
            m_cache.Resize(voxelStart, voxelEnd);
            storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd);
            if (!m_cache.ContainsIsoSurface())
            {
                return(null);
            }

            if (generateMaterials)
            {
                storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, lod, ref voxelStart, ref voxelEnd);
            }
            else
            {
                m_cache.ClearMaterials(0);
            }
            var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod);

            ProfilerShort.Begin("Dual Contouring");
            unsafe
            {
                fixed(byte *voxels = m_cache.Data)
                {
                    var size3d = m_cache.Size3D;

                    Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z);
                    IsoMesher.Calculate(size3d.X, (VoxelData *)voxels, m_buffer);
                }
            }
            ProfilerShort.End();

            if (m_buffer.VerticesCount == 0 && m_buffer.Triangles.Count == 0)
            {
                return(null);
            }

            ProfilerShort.Begin("Geometry post-processing");
            {
                var vertexCellOffset = voxelStart - AffectedRangeOffset;
                var positions        = m_buffer.Positions.GetInternalArray();
                var vertexCells      = m_buffer.Cells.GetInternalArray();
                for (int i = 0; i < m_buffer.VerticesCount; i++)
                {
                    var min = -Vector3.One;
                    var max = Vector3.One;
                    //   Debug.Assert(positions[i].IsInsideInclusive(ref min, ref max));
                    vertexCells[i] += vertexCellOffset;
                }

                float numCellsHalf = 0.5f * (m_cache.Size3D.X - 3);
                m_buffer.PositionOffset = (vertexCellOffset + numCellsHalf) * voxelSize;
                m_buffer.PositionScale  = new Vector3(numCellsHalf * voxelSize);
            }
            ProfilerShort.End();

            // Replace filled mesh with new one.
            // This way prevents allocation of meshes which then end up empty.
            var buffer = m_buffer;

            m_buffer = new MyIsoMesh();
            return(buffer);
        }
        public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials)
        {
            // change range so normal can be computed at edges (expand by 1 in all directions)
            voxelStart -= 1;
            voxelEnd += 1;
            m_cache.Resize(voxelStart, voxelEnd);
            storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd);
            if (!m_cache.ContainsIsoSurface())
            {
                return null;
            }

            if (generateMaterials)
            {
                storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, lod, ref voxelStart, ref voxelEnd);
            }
            else
            {
                m_cache.ClearMaterials(0);
            }
            var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod);

            ProfilerShort.Begin("Dual Contouring");
            unsafe
            {
                fixed (byte* voxels = m_cache.Data)
                {
                    var size3d = m_cache.Size3D;
                    Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z);
                    IsoMesher.Calculate(size3d.X, (VoxelData*)voxels, m_buffer);
                }
            }
            ProfilerShort.End();

            if (m_buffer.VerticesCount == 0 && m_buffer.Triangles.Count == 0)
            {
                return null;
            }

            ProfilerShort.Begin("Geometry post-processing");
            {
                var vertexCellOffset = voxelStart - AffectedRangeOffset;
                var positions = m_buffer.Positions.GetInternalArray();
                var vertexCells = m_buffer.Cells.GetInternalArray();
                for (int i = 0; i < m_buffer.VerticesCount; i++)
                {
                    Debug.Assert(positions[i].IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One));
                    vertexCells[i] += vertexCellOffset;
                }

                double numCellsHalf = 0.5 * (m_cache.Size3D.X - 3);
                m_buffer.PositionOffset = ((Vector3D)vertexCellOffset + numCellsHalf) * (double)voxelSize;
                m_buffer.PositionScale = new Vector3((float)(numCellsHalf * voxelSize));
            }
            ProfilerShort.End();

            // Replace filled mesh with new one.
            // This way prevents allocation of meshes which then end up empty.
            var buffer = m_buffer;
            m_buffer = new MyIsoMesh();
            return buffer;
        }
        public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient, bool doNotCheck)
        {
            m_resultVerticesCounter  = 0;
            m_resultTrianglesCounter = 0;
            m_edgeVertexCalcCounter++;
            m_temporaryVoxelsCounter++;

            CalcPolygCubeSize(lod, storage.Size);

            m_voxelStart = voxelStart;
            //voxelStart = voxelStart;
            //voxelEnd = voxelEnd;
            var ssize = storage.Size;

            m_cache.Resize(voxelStart, voxelEnd);

            // Load content first, check it if it contains isosurface, early exit if it doesn't.
            storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd);

            if (!m_cache.ContainsIsoSurface())
            {
                return(null);
            }

            storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, lod, ref voxelStart, ref voxelEnd);

            ProfilerShort.Begin("Marching cubes");
            {
                //  Size of voxel or cell (in meters) and size of voxel map / voxel cells
                ComputeSizeAndOrigin(lod, storage.Size);


                var      start  = Vector3I.Zero;
                var      end    = voxelEnd - voxelStart - 3;
                Vector3I coord0 = start;


                for (var it = new Vector3I.RangeIterator(ref start, ref end); it.IsValid(); it.GetNext(out coord0))
                {
                    int cubeIndex = 0;
                    if (m_cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                    {
                        cubeIndex |= 1;
                    }
                    if (m_cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                    {
                        cubeIndex |= 2;
                    }
                    if (m_cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                    {
                        cubeIndex |= 4;
                    }
                    if (m_cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                    {
                        cubeIndex |= 8;
                    }
                    if (m_cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                    {
                        cubeIndex |= 16;
                    }
                    if (m_cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                    {
                        cubeIndex |= 32;
                    }
                    if (m_cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                    {
                        cubeIndex |= 64;
                    }
                    if (m_cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL)
                    {
                        cubeIndex |= 128;
                    }

                    //  Cube is entirely in/out of the surface
                    if (MyMarchingCubesConstants.EdgeTable[cubeIndex] == 0)
                    {
                        continue;
                    }

                    //  We can get this voxel content right from cache (not using GetVoxelContent method), because after CopyVoxelContents these array must be filled. But only content, not material, normal, etc.
                    Vector3I tempVoxelCoord0 = ComputeTemporaryVoxelData(m_cache, ref coord0, cubeIndex, lod);

                    //  Create the triangles
                    CreateTriangles(ref coord0, cubeIndex, ref tempVoxelCoord0);
                }
            }
            ProfilerShort.End();


            double numCellsHalf     = 0.5f * (m_cache.Size3D.X);
            var    voxelSize        = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod);
            var    vertexCellOffset = voxelStart - AffectedRangeOffset;

            IMyIsoMesherOutputBuffer isomesh = new MyIsoMesh();


            for (int i = 0; i < m_resultVerticesCounter; i++)
            {
                var pos = (m_resultVertices[i].Position - (Vector3)storage.Size / 2) / storage.Size;
                m_resultVertices[i].Position      = pos;
                m_resultVertices[i].PositionMorph = pos;
                m_resultVertices[i].NormalMorph   = m_resultVertices[i].Normal;
                m_resultVertices[i].MaterialMorph = m_resultVertices[i].Material;
                m_resultVertices[i].AmbientMorph  = m_resultVertices[i].Ambient;
            }

            for (int i = 0; i < m_resultVerticesCounter; i++)
            {
                isomesh.WriteVertex(ref m_resultVertices[i].Cell, ref m_resultVertices[i].Position, ref m_resultVertices[i].Normal, (byte)m_resultVertices[i].Material, m_resultVertices[i].Ambient);
            }

            for (int i = 0; i < m_resultTrianglesCounter; i++)
            {
                isomesh.WriteTriangle(m_resultTriangles[i].VertexIndex0, m_resultTriangles[i].VertexIndex1, m_resultTriangles[i].VertexIndex2);
            }

            var mIsoMesh = (MyIsoMesh)isomesh;

            mIsoMesh.PositionOffset = storage.Size / 2;
            mIsoMesh.PositionScale  = storage.Size;
            mIsoMesh.CellStart      = voxelStart;
            mIsoMesh.CellEnd        = voxelEnd;

            var vertexCells = mIsoMesh.Cells.GetInternalArray();

            for (int i = 0; i < mIsoMesh.VerticesCount; i++)
            {
                vertexCells[i] += vertexCellOffset;
            }

            return((MyIsoMesh)isomesh);
        }
        private void ProcessHighVertex(MyIsoMesh mesh, int vertexIndex, ref MyClipmapCellMeshMetadata meta, out MyVoxelVertex vertex)
        {
            vertex = new MyVoxelVertex();
            vertex.Position = mesh.Positions[vertexIndex];
            vertex.Normal = mesh.Normals[vertexIndex];
            vertex.Material = mesh.Materials[vertexIndex];
            vertex.Ambient = mesh.Ambient[vertexIndex];
            vertex.Cell = mesh.Cells[vertexIndex];
            vertex.PositionMorph = vertex.Position;
            vertex.NormalMorph = vertex.Normal;
            vertex.MaterialMorph = vertex.Material;
            vertex.AmbientMorph = vertex.Ambient;
            
            
            //Vertex morph;
            //Vector3I lowerLodCell = (mesh.Cells[vertexIndex]) >> 1;

            //if (m_morphMap.TryGetValue(lowerLodCell, out morph))
            //{
            //    vertex.PositionMorph = morph.Target.Position;
            //    vertex.NormalMorph = morph.Target.Normal;
            //    vertex.MaterialMorph = morph.Target.Material;
            //    vertex.AmbientMorph = morph.Target.Ambient;
            //}
            //else
            //{

            //}

            //if (m_lowVertices.Count > 0)
            //{

            //    float closestDistance = float.MaxValue;
            //    int closestLowVertex = -1;
            //    for (int i = 0; i < m_lowVertices.Count; i++)
            //    {
            //        float dist = Vector3.DistanceSquared(vertex.Position, m_lowVertices[i].Target.Position);
            //        if (dist < closestDistance)
            //        {
            //            closestDistance = dist;
            //            closestLowVertex = i;
            //        }
            //    }

            //    vertex.PositionMorph = m_lowVertices[closestLowVertex].Target.Position;
            //    vertex.NormalMorph = m_lowVertices[closestLowVertex].Target.Normal;
            //    vertex.MaterialMorph = m_lowVertices[closestLowVertex].Target.Material;
            //    vertex.AmbientMorph = m_lowVertices[closestLowVertex].Target.Ambient;

            //    m_lowToHighMapping[closestLowVertex].Add(vertexIndex);
            //    m_highToLowMapping.Add(closestLowVertex);
            //}

            m_highVertices.Add(vertex);
        }
        private void AddMeshTriangles(MyIsoMesh mesh, Vector3 offset, Matrix rotation, Matrix ownRotation)
        {
            for (int i = 0; i < mesh.TrianglesCount; i++)
            {
                ushort a = mesh.Triangles[i].VertexIndex0;
                ushort b = mesh.Triangles[i].VertexIndex1;
                ushort c = mesh.Triangles[i].VertexIndex2;
                m_worldVertices.Triangles.Add(m_worldVertices.VerticesMaxValue + c);
                m_worldVertices.Triangles.Add(m_worldVertices.VerticesMaxValue + b);
                m_worldVertices.Triangles.Add(m_worldVertices.VerticesMaxValue + a);
            }

            for (int i = 0; i < mesh.VerticesCount; i++)
            {
                Vector3 vert;
                mesh.GetUnpackedPosition(i, out vert);
                Vector3.Transform(ref vert, ref ownRotation, out vert);
                vert -= offset;
                Vector3.Transform(ref vert, ref rotation, out vert);

                m_worldVertices.Vertices.Add(vert);
            }

            m_worldVertices.VerticesMaxValue += mesh.VerticesCount;
        }
        internal void BuildCell(
            MyPrecalcJobRender.Args args,
            MyIsoMesh highResMesh,
            MyIsoMesh lowResMesh,
            List<MyClipmapCellBatch> outBatches,
            out Vector3D positionOffset,
            out Vector3 positionScale,
            out BoundingBox localBoundingBox)
        {
            Debug.Assert(highResMesh != null);

            {
                positionOffset = highResMesh.PositionOffset;
                positionScale = highResMesh.PositionScale;
            }

            {
                // Find low resolution LoD vertices to map to
                float vertexCellSizeInParentLod = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << (args.Cell.Lod + 1));
                float collisionThreshold = 0.0001f * vertexCellSizeInParentLod * vertexCellSizeInParentLod;
                if (lowResMesh != null)
                {
                    /*
                     * Derived transformation of normalized coordinates from low res mesh to high res mesh.
                     * _l is for low res, _h for high res, x is vertex position
                     x = x_l * scale_l + offset_l
                     x_h = (x - offset_h) / scale_h
                     x_h = ((x_l * scale_l + offset_l) - offset_h) / scale_h
                     x_h = (x_l * scale_l + offset_l - offset_h) / scale_h
                     x_h = x_l * (scale_l / scale_h) + ((offset_l - offset_h) / scale_h)
                     */
                    Vector3 morphOffset, morphScale;
                    morphScale = lowResMesh.PositionScale / highResMesh.PositionScale;
                    morphOffset = (Vector3)(lowResMesh.PositionOffset - highResMesh.PositionOffset) / highResMesh.PositionScale;
                    for (int i = 0; i < lowResMesh.VerticesCount; ++i)
                    {
                        var vertex = new Vertex
                        {
                            Target = new MorphData {
                                Position = lowResMesh.Positions[i] * morphScale + morphOffset,
                                Normal = lowResMesh.Normals[i],
                                Material = lowResMesh.Materials[i],
                            },
                            Cell = lowResMesh.Cells[i],
                        };

                        if (m_morphMap.ContainsKey(vertex.Cell))
                        {
                            var collidedVertex = m_morphMap[vertex.Cell];
                            Debug.Assert(collidedVertex.Cell == vertex.Cell);

                            var collisionDist2 = (collidedVertex.Target.Position - vertex.Target.Position).LengthSquared();
                            if (collisionDist2 > collisionThreshold)
                            {
                                //Debug.Fail(string.Format("Collision between vertices! {0} > {1}", collisionDist2, collisionThreshold));
                                m_collisionList.Add(collidedVertex);
                            }
                        }
                        m_morphMap[vertex.Cell] = vertex;
                    }
                }

#if false
                ProcessMorphTargetCollisions(args, vertexCellSizeInParentLod);
#endif

#if false
                EnsureMorphTargetExists(args, highResMesh);
#endif
            }

            localBoundingBox = BoundingBox.CreateInvalid();

            //  Increase lookup count, so we will think that all vertices in helper arrays are new
            foreach (var lookup in SM_BatchLookups.Values)
            {
                lookup.ResetBatch();
            }

            for (int i = 0; i < highResMesh.Triangles.Count; i++)
            {
                MyVoxelTriangle srcTriangle = highResMesh.Triangles[i];
                MyVoxelVertex vertex0, vertex1, vertex2;
                ProcessVertex(highResMesh, srcTriangle.VertexIndex0, ref localBoundingBox, ref positionScale, ref positionOffset, out vertex0);
                ProcessVertex(highResMesh, srcTriangle.VertexIndex1, ref localBoundingBox, ref positionScale, ref positionOffset, out vertex1);
                ProcessVertex(highResMesh, srcTriangle.VertexIndex2, ref localBoundingBox, ref positionScale, ref positionOffset, out vertex2);

                if (MyPerGameSettings.ConstantVoxelAmbient.HasValue)
                {
                    vertex0.Ambient = vertex1.Ambient = vertex2.Ambient = MyPerGameSettings.ConstantVoxelAmbient.Value;
                }

                if (vertex0.Material == vertex1.Material &&
                    vertex0.Material == vertex2.Material &&
                    vertex0.Material == vertex0.MaterialMorph &&
                    vertex0.Material == vertex1.MaterialMorph &&
                    vertex0.Material == vertex2.MaterialMorph)
                { // single material
                    var matIdx = vertex0.Material;

                    //  This is single-texture triangleVertexes, so we can choose material from any edge
                    SingleMaterialHelper materialHelper;
                    if (!SM_Helpers.TryGetValue(matIdx, out materialHelper))
                    {
                        if (!SM_HelperPool.TryDequeue(out materialHelper))
                            materialHelper = new SingleMaterialHelper();
                        materialHelper.Material = matIdx;
                        SM_Helpers.Add(matIdx, materialHelper);
                    }

                    VertexInBatchLookup batchLookup;
                    if (!SM_BatchLookups.TryGetValue(matIdx, out batchLookup))
                    {
                        if (!SM_BatchLookupPool.TryDequeue(out batchLookup))
                            batchLookup = new VertexInBatchLookup();
                        SM_BatchLookups.Add(matIdx, batchLookup);
                    }

                    AddVertexToBuffer(materialHelper, ref vertex0, batchLookup, srcTriangle.VertexIndex0);
                    AddVertexToBuffer(materialHelper, ref vertex1, batchLookup, srcTriangle.VertexIndex1);
                    AddVertexToBuffer(materialHelper, ref vertex2, batchLookup, srcTriangle.VertexIndex2);

                    //  Add indices
                    int nextTriangleIndex = materialHelper.IndexCount;
                    materialHelper.Indices[nextTriangleIndex + 0] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex0);
                    materialHelper.Indices[nextTriangleIndex + 1] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex1);
                    materialHelper.Indices[nextTriangleIndex + 2] = batchLookup.GetIndexInBatch(srcTriangle.VertexIndex2);
                    materialHelper.IndexCount += 3;

                    if ((materialHelper.VertexCount >= MAX_VERTICES_COUNT_STOP) ||
                        (materialHelper.IndexCount >= MAX_INDICES_COUNT_STOP))
                    {
                        //  If this batch is almost full (or is full), we end it and start with new one
                        EndSingleMaterial(materialHelper, outBatches);
                    }
                }
                else
                {
                    Vector3I materials = GetMaterials(ref vertex0, ref vertex1, ref vertex2);
                    var voxelMaterialCount = MyDefinitionManager.Static.VoxelMaterialCount;
                    int id = materials.X + voxelMaterialCount * (materials.Y + materials.Z * voxelMaterialCount);

                    // Assign current material
                    MultiMaterialHelper helper = null;
                    if (!MM_Helpers.TryGetValue(id, out helper))
                    {
                        if (!MM_HelperPool.TryDequeue(out helper))
                            helper = new MultiMaterialHelper();
                        helper.Material0 = materials.X;
                        helper.Material1 = materials.Y;
                        helper.Material2 = materials.Z;
                        MM_Helpers.Add(id, helper);
                    }

                    helper.AddVertex(ref vertex0);
                    helper.AddVertex(ref vertex1);
                    helper.AddVertex(ref vertex2);

                    if (helper.Vertices.Count >= MAX_VERTICES_COUNT_STOP)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                }
            }

            { //renderCell.End();
                foreach (var helper in SM_Helpers.Values)
                {
                    Debug.Assert(helper != null);
                    if (helper.IndexCount > 0)
                    {
                        EndSingleMaterial(helper, outBatches);
                    }
                    helper.IndexCount = 0;
                    helper.VertexCount = 0;
                    SM_HelperPool.Enqueue(helper);
                }
                SM_Helpers.Clear();

                foreach (var helper in MM_Helpers.Values)
                {
                    if (helper.Vertices.Count > 0)
                    {
                        EndMultiMaterial(helper, outBatches);
                    }
                    helper.Vertices.Clear();
                    MM_HelperPool.Enqueue(helper);
                }
                MM_Helpers.Clear();

                foreach (var lookup in SM_BatchLookups.Values)
                {
                    SM_BatchLookupPool.Enqueue(lookup);
                }
                SM_BatchLookups.Clear();
            }

            m_morphMap.Clear();
        }
        internal HkBvCompressedMeshShape CreateShape(MyIsoMesh mesh)
        {
            // mk:NOTE This method must be thread safe. Called from worker threads.

            if (mesh == null || mesh.TrianglesCount == 0 || mesh.VerticesCount == 0)
                return (HkBvCompressedMeshShape)HkShape.Empty;

            List<int> indexList = new List<int>(mesh.TrianglesCount * 3);
            List<Vector3> vertexList = new List<Vector3>(mesh.VerticesCount);

            for (int i = 0; i < mesh.TrianglesCount; i++)
            {
                indexList.Add(mesh.Triangles[i].VertexIndex0);
                indexList.Add(mesh.Triangles[i].VertexIndex2);
                indexList.Add(mesh.Triangles[i].VertexIndex1);
            }

            // mk:TODO Unify denormalizing of positions with what is in MyIsoMesh.
            var positionOffset = mesh.PositionOffset - m_voxelMap.StorageMin * MyVoxelConstants.VOXEL_SIZE_IN_METRES;
            var positions = mesh.Positions.GetInternalArray();
            for (int i = 0; i < mesh.VerticesCount; i++)
            {
                vertexList.Add(positions[i] * mesh.PositionScale + positionOffset);
            }
            using (var cellGeometry = new HkGeometry(vertexList, indexList))
            {
                var result = new HkBvCompressedMeshShape(cellGeometry, null, null, HkWeldingType.None, MyPerGameSettings.PhysicsConvexRadius);
                Debug.Assert(result.Base.ReferenceCount == 1);
                return result;
            }
        }
 public static bool IsEmpty(MyIsoMesh self)
 {
     return(self == null || self.Triangles.Count == 0);
 }