コード例 #1
0
            internal void InvalidateRange(Vector3I lodMin, Vector3I lodMax)
            {
                //              MyLog.Default.WriteLine("InvalidateRange Lod: " + m_lodIndex + " Min: " + lodMin + " Max: " + lodMax);

                var cell = new MyCellCoord(m_lodIndex, lodMin);

                for (var it = new Vector3I_RangeIterator(ref lodMin, ref lodMax);
                     it.IsValid(); it.GetNext(out cell.CoordInLod))
                {
                    MyClipmap_CellData data;
                    var id = cell.PackId64();
//                    MyLog.Default.WriteLine("Setting to: m_lodIndex " + cell.Lod + " Coord: " + cell.CoordInLod);


                    if (m_storedCellData.TryGetValue(id, out data))
                    {
                        data.State = CellState.Invalid;
                        //MyLog.Default.WriteLine("Really set to: m_lodIndex " + cell.Lod + " Coord: " + cell.CoordInLod);
                    }

                    if (MyClipmap.UseCache)
                    {
                        var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, id);
                        var cachedCell    = MyClipmap.CellsCache.Read(clipmapCellId);
                        if (cachedCell != null)
                        {
                            cachedCell.State = CellState.Invalid;
                        }
                    }
                }
            }
コード例 #2
0
            /// <summary>
            /// Checks only immediate children (any deeper would take too long).
            /// </summary>
            private static bool ChildrenWereLoaded(LodLevel childLod, ref MyCellCoord thisLodCell)
            {
                if (childLod == null)
                {
                    return(false);
                }

                Debug.Assert(thisLodCell.Lod == childLod.m_lodIndex + 1);

                var childLodCell = new MyCellCoord();

                childLodCell.Lod = childLod.m_lodIndex;
                var shiftToChild = MyVoxelCoordSystems.RenderCellSizeShiftToMoreDetailed(thisLodCell.Lod);
                var start        = thisLodCell.CoordInLod << shiftToChild;
                var end          = start + ((1 << shiftToChild) >> 1);

                Vector3I.Max(ref childLod.m_lodSizeMinusOne, ref Vector3I.Zero, out childLod.m_lodSizeMinusOne);
                Vector3I.Min(ref end, ref childLod.m_lodSizeMinusOne, out end);
                childLodCell.CoordInLod = start;
                for (var it = new Vector3I_RangeIterator(ref start, ref end);
                     it.IsValid(); it.GetNext(out childLodCell.CoordInLod))
                {
                    var key = childLodCell.PackId64();
                    MyClipmap_CellData data;
                    if (!childLod.m_storedCellData.TryGetValue(key, out data) || !data.WasLoaded)
                    {
                        return(false);
                    }
                }

                return(true);
            }
コード例 #3
0
        // Actually, this function marks even cubes around the block to make sure that any changes caused in their triangles
        // will be reflected in the navigation mesh.
        public void MarkBlockChanged(MySlimBlock block)
        {
            Vector3I min = block.Min - Vector3I.One;
            Vector3I max = block.Max + Vector3I.One;

            Vector3I pos = min;
            for (var it = new Vector3I.RangeIterator(ref block.Min, ref block.Max); it.IsValid(); it.GetNext(out pos))
            {
                m_changedCubes.Add(pos);
            }

            Vector3I minCell = CubeToCell(ref min);
            Vector3I maxCell = CubeToCell(ref max);

            pos = minCell;
            for (var it = new Vector3I.RangeIterator(ref minCell, ref maxCell); it.IsValid(); it.GetNext(out pos))
            {
                m_changedCells.Add(pos);

                MyCellCoord cellCoord = new MyCellCoord(0, pos);
                ulong packedCell = cellCoord.PackId64();

                TryClearCell(packedCell);
            }
        }
コード例 #4
0
            /// <summary>
            /// Checks only immediate children (any deeper would take too long).
            /// </summary>
            private static bool ChildrenWereLoaded(LodLevel childLod, ref MyCellCoord thisLodCell)
            {
                if (childLod == null || !childLod.Visible)
                    return false;

                Debug.Assert(thisLodCell.Lod == childLod.m_lodIndex + 1);

                var childLodCell = new MyCellCoord();
                childLodCell.Lod = childLod.m_lodIndex;
                var start = thisLodCell.CoordInLod << 1;
                var end = start + 1;

                Vector3I.Min(ref end, ref childLod.m_lodSizeMinusOne, out end);
                for (childLodCell.CoordInLod.Z = start.Z; childLodCell.CoordInLod.Z <= end.Z; ++childLodCell.CoordInLod.Z)
                for (childLodCell.CoordInLod.Y = start.Y; childLodCell.CoordInLod.Y <= end.Y; ++childLodCell.CoordInLod.Y)
                for (childLodCell.CoordInLod.X = start.X; childLodCell.CoordInLod.X <= end.X; ++childLodCell.CoordInLod.X)
                {
                    var key = childLodCell.PackId64();
                    CellData data;
                    if (!childLod.m_storedCellData.TryGetValue(key, out data))
                    {
                        return false;
                    }

                    if (!data.WasLoaded)
                    {
                        return false;
                    }
                }

                return true;
            }
コード例 #5
0
            /// <summary>
            /// Checks ancestor nodes recursively.
            /// </summary>
            private static bool WasAncestorCellLoaded(LodLevel parentLod, ref MyCellCoord thisLodCell)
            {
                if (parentLod == null || !parentLod.m_fitsInFrustum)
                {
                    return(true);
                }

                Debug.Assert(thisLodCell.Lod == parentLod.m_lodIndex - 1);

                var shiftToParent = MyVoxelCoordSystems.RenderCellSizeShiftToLessDetailed(thisLodCell.Lod);
                var parentCell    = new MyCellCoord(thisLodCell.Lod + 1, thisLodCell.CoordInLod >> shiftToParent);
                MyClipmap_CellData data;

                if (parentLod.m_storedCellData.TryGetValue(parentCell.PackId64(), out data))
                {
                    return(data.WasLoaded);
                }

                LodLevel ancestor;

                if (parentLod.m_clipmap.m_lodLevels.TryGetValue(parentLod.m_lodIndex + 1, out ancestor))
                {
                    return(WasAncestorCellLoaded(ancestor, ref parentCell));
                }
                else
                {
                    return(false);
                }
            }
コード例 #6
0
ファイル: MyClipmap.cs プロジェクト: rwohleb/SpaceEngineers
            /// <summary>
            /// Checks ancestor nodes recursively. Typically, this checks at most 9 nodes or so (depending on settings).
            /// </summary>
            private static bool WasAncestorCellLoaded(LodLevel parentLod, ref MyCellCoord thisLodCell)
            {
                if (parentLod == null || !parentLod.m_fitsInFrustum || !parentLod.Visible)
                {
                    return(true);
                }

                Debug.Assert(thisLodCell.Lod == parentLod.m_lodIndex - 1);

                var      parentCell = new MyCellCoord(thisLodCell.Lod + 1, thisLodCell.CoordInLod >> 1);
                CellData data;

                if (parentLod.m_storedCellData.TryGetValue(parentCell.PackId64(), out data))
                {
                    return(data.WasLoaded);
                }

                LodLevel ancestor;

                if (parentLod.m_parent.m_lodLevels.TryGetValue(parentLod.m_lodIndex + 1, out ancestor))
                {
                    return(WasAncestorCellLoaded(ancestor, ref parentCell));
                }
                else
                {
                    return(false);
                }
            }
コード例 #7
0
 internal void InvalidateRange(Vector3I lodMin, Vector3I lodMax)
 {
     var cell = new MyCellCoord(m_lodIndex, lodMin);
     for (var it = new Vector3I.RangeIterator(ref lodMin, ref lodMax);
         it.IsValid(); it.GetNext(out cell.CoordInLod))
     {
         CellData data;
         var id = cell.PackId64();
         if (m_storedCellData.TryGetValue(id, out data))
         {
             data.State = CellState.Invalid;
         }
     }
 }
コード例 #8
0
 internal void InvalidateRange(Vector3I lodMin, Vector3I lodMax)
 {
     var cell = new MyCellCoord(m_lodIndex, lodMin);
     for (var it = new Vector3I.RangeIterator(ref lodMin, ref lodMax);
         it.IsValid(); it.GetNext(out cell.CoordInLod))
     {
         CellData data;
         var id = cell.PackId64();
         using (m_storedCellDataLock.AcquireSharedUsing())
         {
             if (m_storedCellData.TryGetValue(id, out data))
             {
                 data.State = CellState.Invalid;
             }
         }
     }
 }
コード例 #9
0
            private void UnclipCell(RequestCollector collector, MyCellCoord cell, bool isVisible)
            {
                var cellId = cell.PackId64();
                var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId);
                MyClipmap_CellData data;

                if (isVisible)
                {
                    bool highPriority = true;

                    if (m_clippedCells.TryGetValue(cellId, out data))
                    {
                        m_clippedCells.Remove(cellId);
                    }
                    else
                    {
                        highPriority = false;

                        CellBlendData blendData;
                        if (!m_blendedCells.TryGetValue(cellId, out blendData))
                        {
                            data = CellsCache.Read(clipmapCellId);

                            if (data == null) //cache miss
                            {
                                data = new MyClipmap_CellData();
                                ClippingCacheMisses++;
                            }
                            else
                            {
                                //cache hit
                                ClippingCacheHits++;

                                //System.Diagnostics.Debug.Assert((!data.InScene && data.Cell != null) || data.Cell == null, "Not allowed cell state");
                                data.InScene = false;
                                if (data.Cell != null)
                                {
                                    m_nonEmptyCells[cellId] = data;
                                }
                            }
                        }
                        else
                        {
                            data = blendData.CellData;
                            if (blendData.State == BlendState.Removing)
                                blendData.UndoAfterFinish = true;
                            if (data.Cell != null)
                            {
                                m_nonEmptyCells[cellId] = data;
                            }
                        }
                    }

                    if (data.State == CellState.Invalid)
                    {
                        if (MyClipmap.UseQueries)
                        {
                            BoundingBoxD bbd;
                            MyVoxelCoordSystems.RenderCellCoordToLocalAABB(ref cell, out bbd);
                            BoundingBox bb = new BoundingBox(bbd);
                            if (m_clipmap.m_prunningFunc == null || m_clipmap.m_prunningFunc(ref bb, false) == ContainmentType.Intersects)
                            {
                                collector.AddRequest(cellId, data, highPriority);
                            }
                            else
                            {
                                data.State = CellState.Loaded;
                                data.WasLoaded = true;
                            }
                        }
                        else
                          collector.AddRequest(cellId, data, highPriority);
                    }
             
                    m_storedCellData.Add(cellId, data);
                    data.ReadyInClipmap = true;
                    data.ClippedOut = false;
                }
                else
                {
                    if (!m_storedCellData.ContainsKey(cellId) && (!PendingCacheCellData.ContainsKey(clipmapCellId) || PendingCacheCellData[clipmapCellId].State == CellState.Invalid) && CellsCache.Read(clipmapCellId) == null)
                    {
                        if (!PendingCacheCellData.TryGetValue(clipmapCellId, out data))
                        {
                            data = new MyClipmap_CellData();
                            PendingCacheCellData.Add(clipmapCellId, data);
                        }

                        if (MyClipmap.UseQueries)
                        {
                            BoundingBoxD bbd;
                            MyVoxelCoordSystems.RenderCellCoordToLocalAABB(ref cell, out bbd);
                            BoundingBox bb = new BoundingBox(bbd);
                            if (m_clipmap.m_prunningFunc == null || m_clipmap.m_prunningFunc(ref bb, false) == ContainmentType.Intersects)
                            {
                                data.State = CellState.Invalid;

                                collector.AddRequest(cellId, data, false);
                            }
                            else
                            {
                                data.State = CellState.Loaded;
                                data.WasLoaded = true;
                            }
                        }
                        else
                        {
                            data.State = CellState.Invalid;
                            collector.AddRequest(cellId, data, false);
                        }
                    }
                }
            }
コード例 #10
0
ファイル: MyClipmap.cs プロジェクト: Tyrsis/SpaceEngineers-1
            public void Submit()
            {
                ProfilerShort.Begin("RequestCollector.Submit");

                MyCellCoord cell = default(MyCellCoord);

                foreach (var cellId in m_cancelRequests)
                {
                    cell.SetUnpack(cellId);
                    MyRenderProxy.CancelClipmapCell(m_clipmapId, cell);
                    bool removed = m_sentRequests.Remove(cellId);
                    Debug.Assert(removed);
                }

                foreach (var highPriorityRequest in m_unsentRequestsHigh)
                {
                    cell.SetUnpack(highPriorityRequest);
                    MyRenderProxy.RequireClipmapCell(m_clipmapId, cell, highPriority: true);
                }
                m_unsentRequestsHigh.Clear();

                int addedCount = 0;

                for (int i = m_unsentRequestsLow.Length - 1; i >= 0; i--)
                {
                    var unsent = m_unsentRequestsLow[i];
                    while (0 < unsent.Count && m_sentRequests.Count < m_maxRequests)
                    {
                        var cellId = unsent.FirstElement();

                        cell.SetUnpack(cellId);
                        // Do Z-order style iteration of siblings that also need to
                        // be requested. This ensures faster processing of cells and
                        // shorter time when both lods are rendered.
                        var baseCoord = (cell.CoordInLod >> 1) << 1;
                        var offset    = Vector3I.Zero;
                        for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref Vector3I.One);
                             it.IsValid(); it.GetNext(out offset))
                        {
                            cell.CoordInLod = baseCoord + offset;
                            cellId          = cell.PackId64();
                            if (!unsent.Remove(cellId))
                            {
                                continue;
                            }

                            Debug.Assert(!m_cancelRequests.Contains(cellId));
                            MyRenderProxy.RequireClipmapCell(m_clipmapId, cell, highPriority: false);
                            bool added = m_sentRequests.Add(cellId);
                            Debug.Assert(added);
                            addedCount++;
                        }
                    }

                    // When set reaches reasonably small size, stop freeing memory
                    if (unsent.Count > 100)
                    {
                        unsent.TrimExcess();
                    }
                }

                m_cancelRequests.Clear();

                ProfilerShort.End();
            }
コード例 #11
0
            private void UnclipCell(RequestCollector collector, MyCellCoord cell, bool isVisible)
            {
                var      cellId        = cell.PackId64();
                var      clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId);
                CellData data;

                if (isVisible)
                {
                    bool highPriority = true;

                    if (m_clippedCells.TryGetValue(cellId, out data))
                    {
                        m_clippedCells.Remove(cellId);
                    }
                    else
                    {
                        highPriority = false;

                        CellBlendData blendData;
                        if (!m_blendedCells.TryGetValue(cellId, out blendData))
                        {
                            data = CellsCache.Read(clipmapCellId);

                            if (data == null) //cache miss
                            {
                                data = new CellData();
                                ClippingCacheMisses++;
                            }
                            else
                            {
                                //cache hit
                                ClippingCacheHits++;

                                //System.Diagnostics.Debug.Assert((!data.InScene && data.Cell != null) || data.Cell == null, "Not allowed cell state");
                                data.InScene = false;
                                if (data.Cell != null)
                                {
                                    m_nonEmptyCells[cellId] = data;
                                }
                            }
                        }
                        else
                        {
                            data = blendData.CellData;
                            if (blendData.State == BlendState.Removing)
                            {
                                blendData.UndoAfterFinish = true;
                            }
                            if (data.Cell != null)
                            {
                                m_nonEmptyCells[cellId] = data;
                            }
                        }
                    }

                    if (data.State == CellState.Invalid)
                    {
                        if (MyClipmap.UseQueries)
                        {
                            BoundingBoxD bbd;
                            MyVoxelCoordSystems.RenderCellCoordToLocalAABB(ref cell, out bbd);
                            BoundingBox bb = new BoundingBox(bbd);
                            if (m_clipmap.m_prunningFunc == null || m_clipmap.m_prunningFunc(ref bb, false) == ContainmentType.Intersects)
                            {
                                collector.AddRequest(cellId, data, highPriority);
                            }
                            else
                            {
                                data.State     = CellState.Loaded;
                                data.WasLoaded = true;
                            }
                        }
                        else
                        {
                            collector.AddRequest(cellId, data, highPriority);
                        }
                    }

                    m_storedCellData.Add(cellId, data);
                    data.ReadyInClipmap = true;
                    data.ClippedOut     = false;
                }
                else
                {
                    if (!m_storedCellData.ContainsKey(cellId) && (!PendingCacheCellData.ContainsKey(clipmapCellId) || PendingCacheCellData[clipmapCellId].State == CellState.Invalid) && CellsCache.Read(clipmapCellId) == null)
                    {
                        if (!PendingCacheCellData.TryGetValue(clipmapCellId, out data))
                        {
                            data = new CellData();
                            PendingCacheCellData.Add(clipmapCellId, data);
                        }

                        if (MyClipmap.UseQueries)
                        {
                            BoundingBoxD bbd;
                            MyVoxelCoordSystems.RenderCellCoordToLocalAABB(ref cell, out bbd);
                            BoundingBox bb = new BoundingBox(bbd);
                            if (m_clipmap.m_prunningFunc == null || m_clipmap.m_prunningFunc(ref bb, false) == ContainmentType.Intersects)
                            {
                                data.State = CellState.Invalid;

                                collector.AddRequest(cellId, data, false);
                            }
                            else
                            {
                                data.State     = CellState.Loaded;
                                data.WasLoaded = true;
                            }
                        }
                        else
                        {
                            data.State = CellState.Invalid;
                            collector.AddRequest(cellId, data, false);
                        }
                    }
                }
            }
コード例 #12
0
        private MyNavigationTriangle GetClosestNavigationTriangle(ref Vector3 point, ref float closestDistanceSq)
        {
            // TODO: When point is completely away (according to BB), return null

            MyNavigationTriangle closestTriangle = null;

            // Convert from world matrix local coords to LeftBottomCorner-based coords
            Vector3 lbcPoint = point + (m_voxelMap.PositionComp.GetPosition() - m_voxelMap.PositionLeftBottomCorner);

            Vector3I closestCellCorner = Vector3I.Round(lbcPoint / m_cellSize);
            for (int i = 0; i < 8; ++i)
            {
                Vector3I cell = closestCellCorner + m_cornerOffsets[i];
                if (!m_processedCells.Contains(cell)) continue;

                MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, cell);
                ulong packedCoord = coord.PackId64();
                MyIntervalList triList = m_higherLevelHelper.TryGetTriangleList(packedCoord);
                if (triList == null) continue;

                foreach (var triIndex in triList)
                {
                    MyNavigationTriangle tri = GetTriangle(triIndex);

                    // TODO: Use triangle centers so far
                    float distSq = Vector3.DistanceSquared(tri.Center, point);
                    if (distSq < closestDistanceSq)
                    {
                        closestDistanceSq = distSq;
                        closestTriangle = tri;
                    }
                }
            }

            return closestTriangle;
        }
コード例 #13
0
        private bool AddCell(Vector3I cellPos)
        {
            MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, cellPos);

            var generatedMesh = MyPrecalcComponent.IsoMesher.Precalc(new MyIsoMesherArgs()
            {
                Storage = m_voxelMap.Storage,
                GeometryCell = coord,
            });

            if (generatedMesh == null)
            {
                m_processedCells.Add(ref cellPos);
                m_higherLevelHelper.AddExplored(ref cellPos);
                return false;
            }

            ulong packedCoord = coord.PackId64();

            List<DebugDrawEdge> debugEdgesList = new List<DebugDrawEdge>();
            m_debugCellEdges[packedCoord] = debugEdgesList;

            MyVoxelPathfinding.CellId cellId = new MyVoxelPathfinding.CellId() { VoxelMap = m_voxelMap, Pos = cellPos };

            MyTrace.Send(TraceWindow.Ai, "Adding cell " + cellPos);

            m_connectionHelper.ClearCell();
            m_vertexMapping.Init(generatedMesh.VerticesCount);

            // Prepare list of possibly intersecting cube grids for voxel-grid navmesh intersection testing
            Vector3D bbMin = m_voxelMap.PositionLeftBottomCorner + (m_cellSize * (new Vector3D(-0.125) + cellPos));
            Vector3D bbMax = m_voxelMap.PositionLeftBottomCorner + (m_cellSize * (Vector3D.One + cellPos));
            BoundingBoxD cellBB = new BoundingBoxD(bbMin, bbMax);
            m_tmpGridList.Clear();
            m_navmeshCoordinator.PrepareVoxelTriangleTests(cellBB, m_tmpGridList);

            Vector3D voxelMapCenter = m_voxelMap.PositionComp.GetPosition();
            Vector3 centerDisplacement = voxelMapCenter - m_voxelMap.PositionLeftBottomCorner;

            // This is needed for correct edge classification - to tell, whether the edges are inner or outer edges of the cell
            ProfilerShort.Begin("Triangle preprocessing");
            for (int i = 0; i < generatedMesh.TrianglesCount; i++)
            {
                ushort a = generatedMesh.Triangles[i].VertexIndex0;
                ushort b = generatedMesh.Triangles[i].VertexIndex1;
                ushort c = generatedMesh.Triangles[i].VertexIndex2;

                Vector3 aPos, bPos, cPos;
                Vector3 vert;

                generatedMesh.GetUnpackedPosition(a, out vert);
                aPos = vert - centerDisplacement;
                generatedMesh.GetUnpackedPosition(b, out vert);
                bPos = vert - centerDisplacement;
                generatedMesh.GetUnpackedPosition(c, out vert);
                cPos = vert - centerDisplacement;

                bool invalidTriangle = false;
                if ((bPos - aPos).LengthSquared() <= MyVoxelConnectionHelper.OUTER_EDGE_EPSILON_SQ)
                {
                    m_vertexMapping.Union(a, b);
                    invalidTriangle = true;
                }
                if ((cPos - aPos).LengthSquared() <= MyVoxelConnectionHelper.OUTER_EDGE_EPSILON_SQ)
                {
                    m_vertexMapping.Union(a, c);
                    invalidTriangle = true;
                }
                if ((cPos - bPos).LengthSquared() <= MyVoxelConnectionHelper.OUTER_EDGE_EPSILON_SQ)
                {
                    m_vertexMapping.Union(b, c);
                    invalidTriangle = true;
                }

                if (invalidTriangle) continue;

                m_connectionHelper.PreprocessInnerEdge(a, b);
                m_connectionHelper.PreprocessInnerEdge(b, c);
                m_connectionHelper.PreprocessInnerEdge(c, a);
            }
            ProfilerShort.End();

            ProfilerShort.Begin("Free face sorting");
            // Ensure that the faces have increasing index numbers
            Mesh.SortFreeFaces();
            ProfilerShort.End();

            m_higherLevelHelper.OpenNewCell(coord);

            ProfilerShort.Begin("Adding triangles");
            for (int i = 0; i < generatedMesh.TrianglesCount; i++)
            {
                ushort a = generatedMesh.Triangles[i].VertexIndex0;
                ushort b = generatedMesh.Triangles[i].VertexIndex1;
                ushort c = generatedMesh.Triangles[i].VertexIndex2;
                ushort setA = (ushort)m_vertexMapping.Find(a);
                ushort setB = (ushort)m_vertexMapping.Find(b);
                ushort setC = (ushort)m_vertexMapping.Find(c);

                if (setA == setB || setB == setC || setA == setC) continue;

                Vector3 aPos, bPos, cPos;
                Vector3 vert;
                generatedMesh.GetUnpackedPosition(a, out vert);
                aPos = vert - centerDisplacement;
                generatedMesh.GetUnpackedPosition(b, out vert);
                bPos = vert - centerDisplacement;
                generatedMesh.GetUnpackedPosition(c, out vert);
                cPos = vert - centerDisplacement;

                if (MyPerGameSettings.NavmeshPresumesDownwardGravity)
                {
                    Vector3 normal = (cPos - aPos).Cross(bPos - aPos);
                    normal.Normalize();
                    if (normal.Dot(ref Vector3.Up) <= Math.Cos(MathHelper.ToRadians(54.0f))) continue;
                }

                Vector3D aTformed = aPos + voxelMapCenter;
                Vector3D bTformed = bPos + voxelMapCenter;
                Vector3D cTformed = cPos + voxelMapCenter;

                bool intersecting = false;
                m_tmpLinkCandidates.Clear();
                m_navmeshCoordinator.TestVoxelNavmeshTriangle(ref aTformed, ref bTformed, ref cTformed, m_tmpGridList, m_tmpLinkCandidates, out intersecting);
                if (intersecting)
                {
                    m_tmpLinkCandidates.Clear();
                    continue;
                }

                if (!m_connectionHelper.IsInnerEdge(a, b)) debugEdgesList.Add(new DebugDrawEdge(aTformed, bTformed));
                if (!m_connectionHelper.IsInnerEdge(b, c)) debugEdgesList.Add(new DebugDrawEdge(bTformed, cTformed));
                if (!m_connectionHelper.IsInnerEdge(c, a)) debugEdgesList.Add(new DebugDrawEdge(cTformed, aTformed));

                int edgeAB = m_connectionHelper.TryGetAndRemoveEdgeIndex(b, a, ref bPos, ref aPos);
                int edgeBC = m_connectionHelper.TryGetAndRemoveEdgeIndex(c, b, ref cPos, ref bPos);
                int edgeCA = m_connectionHelper.TryGetAndRemoveEdgeIndex(a, c, ref aPos, ref cPos);
                int formerAB = edgeAB;
                int formerBC = edgeBC;
                int formerCA = edgeCA;

                ProfilerShort.Begin("AddTriangle");
                var tri = AddTriangle(ref aPos, ref bPos, ref cPos, ref edgeAB, ref edgeBC, ref edgeCA);
                ProfilerShort.End();

                CheckMeshConsistency();

                m_higherLevelHelper.AddTriangle(tri.Index);

                if (formerAB == -1) m_connectionHelper.AddEdgeIndex(a, b, ref aPos, ref bPos, edgeAB);
                if (formerBC == -1) m_connectionHelper.AddEdgeIndex(b, c, ref bPos, ref cPos, edgeBC);
                if (formerCA == -1) m_connectionHelper.AddEdgeIndex(c, a, ref cPos, ref aPos, edgeCA);

                // TODO: Instead of this, just add the tri into a list of tris that want to connect with the link candidates
                //m_navmeshCoordinator.TryAddVoxelNavmeshLinks(tri, cellId, m_tmpLinkCandidates);
                foreach (var candidate in m_tmpLinkCandidates)
                {
                    List<MyNavigationPrimitive> primitives = null;
                    if (!m_tmpCubeLinkCandidates.TryGetValue(candidate, out primitives))
                    {
                        primitives = m_primitiveListPool.Allocate();
                        m_tmpCubeLinkCandidates.Add(candidate, primitives);
                    }
                    
                    primitives.Add(tri);
                }
                m_tmpLinkCandidates.Clear();
            }
            ProfilerShort.End();

            m_tmpGridList.Clear();
            m_connectionHelper.ClearCell();
            m_vertexMapping.Clear();

            Debug.Assert(!m_processedCells.Contains(ref cellPos));
            m_processedCells.Add(ref cellPos);
            m_higherLevelHelper.AddExplored(ref cellPos);

            // Find connected components in the current cell's subgraph of the navigation mesh
            m_higherLevelHelper.ProcessCellComponents();
            m_higherLevelHelper.CloseCell();

            // Create navmesh links using the navmesh coordinator, taking into consideration the high level components
            m_navmeshCoordinator.TryAddVoxelNavmeshLinks2(cellId, m_tmpCubeLinkCandidates);
            m_navmeshCoordinator.UpdateVoxelNavmeshCellHighLevelLinks(cellId);

            foreach (var candidate in m_tmpCubeLinkCandidates)
            {
                candidate.Value.Clear();
                m_primitiveListPool.Deallocate(candidate.Value);
            }
            m_tmpCubeLinkCandidates.Clear();

            return true;
        }
コード例 #14
0
 private void ComputeIsEmptyLookup(MyCellCoord cell, out ulong outCacheKey, out int outBit)
 {
     var offset = cell.CoordInLod % 4;
     cell.CoordInLod >>= 2;
     Debug.Assert(offset.IsInsideInclusive(Vector3I.Zero, new Vector3I(3)));
     outCacheKey = cell.PackId64();
     outBit = offset.X + 4 * (offset.Y + 4 * offset.Z);
     Debug.Assert((uint)outBit < 64u);
 }
コード例 #15
0
        /// <param name="minVoxelChanged">Inclusive min.</param>
        /// <param name="maxVoxelChanged">Inclusive max.</param>
        private void storage_RangeChanged(Vector3I minChanged, Vector3I maxChanged, MyStorageDataTypeFlags changedData)
        {
            MyPrecalcComponent.AssertUpdateThread();

            ProfilerShort.Begin("MyVoxelGeometry.storage_RangeChanged");

            minChanged -= MyPrecalcComponent.InvalidatedRangeInflate;
            maxChanged += MyPrecalcComponent.InvalidatedRangeInflate;
            m_storage.ClampVoxelCoord(ref minChanged);
            m_storage.ClampVoxelCoord(ref maxChanged);
            var minCellChanged = minChanged >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS;
            var maxCellChanged = maxChanged >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS;
            using (m_lock.AcquireExclusiveUsing())
            {
                if (minCellChanged == Vector3I.Zero && maxCellChanged == m_cellsCount - 1)
                {
                    m_cellsByCoordinate.Clear();
                    m_coordinateToMesh.Clear();
                    m_isEmptyCache.Reset();
                }
                else
                {
                    MyCellCoord cell = new MyCellCoord();
                    cell.CoordInLod = minCellChanged;
                    for (var it = new Vector3I_RangeIterator(ref minCellChanged, ref maxCellChanged); it.IsValid(); it.GetNext(out cell.CoordInLod))
                    {
                        var key = cell.PackId64();
                        m_cellsByCoordinate.Remove(key);
                        m_coordinateToMesh.Remove(key);
                        SetEmpty(ref cell, false);
                    }
                }
            }

            ProfilerShort.End();
        }
コード例 #16
0
        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;
            }
        }
コード例 #17
0
        public void InvalidateRange(Vector3I minVoxelChanged, Vector3I maxVoxelChanged)
        {
            minVoxelChanged -= MyPrecalcComponent.InvalidatedRangeInflate + 1;
            maxVoxelChanged += MyPrecalcComponent.InvalidatedRangeInflate + 1;
            m_voxelMap.Storage.ClampVoxelCoord(ref minVoxelChanged);
            m_voxelMap.Storage.ClampVoxelCoord(ref maxVoxelChanged);

            Vector3I minCellLod0, maxCellLod0;
            minVoxelChanged -= m_voxelMap.StorageMin;
            maxVoxelChanged -= m_voxelMap.StorageMin;

            MyVoxelCoordSystems.VoxelCoordToRenderCellCoord(0, ref minVoxelChanged, out minCellLod0);
            MyVoxelCoordSystems.VoxelCoordToRenderCellCoord(0, ref maxVoxelChanged, out maxCellLod0);

            MyRenderProxy.InvalidateClipmapRange(m_renderObjectIDs[0], minCellLod0, maxCellLod0);

            if (minCellLod0 == Vector3I.Zero &&
                maxCellLod0 == ((m_voxelMap.Storage.Size - 1) >> MyVoxelCoordSystems.RenderCellSizeInLodVoxelsShift(0)))
            {
                m_renderWorkTracker.InvalidateAll();
                m_mergeWorkTracker.InvalidateAll();
            }
            else
            {
                for (int i = 0; i < MyCellCoord.MAX_LOD_COUNT; ++i)
                {
                    var minCell = minCellLod0 >> i;
                    var maxCell = maxCellLod0 >> i;
                    var cellCoord = new MyCellCoord(i, ref minCell);
                    for (var it = new Vector3I_RangeIterator(ref minCell, ref maxCell);
                        it.IsValid(); it.GetNext(out cellCoord.CoordInLod))
                    {
                        m_renderWorkTracker.Invalidate(cellCoord.PackId64());
                        m_mergeWorkTracker.Invalidate(cellCoord.PackId64());
                    }
                }
            }
        }
コード例 #18
0
        internal void OnCellRequest(MyCellCoord cell, Func<int> priorityFunction, Action<Color> debugDraw)
        {
            ProfilerShort.Begin("OnCellRequest");

            try
            {
                var workId = cell.PackId64();
          
                MyPrecalcJobRender.Start(new MyPrecalcJobRender.Args
                {
                    Storage = m_voxelMap.Storage,
                    ClipmapId = ClipmapId,
                    Cell = cell,
                    WorkId = workId,
                    RenderWorkTracker = m_renderWorkTracker,
                    Priority = priorityFunction,
                    DebugDraw = debugDraw,
                });
            }
            finally
            {
                ProfilerShort.End();
            }
        }
コード例 #19
0
        private static void WriteRange(
            ref WriteRangeArgs args,
            byte defaultData,
            int lodIdx,
            Vector3I lodCoord,
            ref Vector3I min,
            ref Vector3I max)
        {
            MyOctreeNode node = new MyOctreeNode();
            {
                MyCellCoord leaf = new MyCellCoord(lodIdx - LeafLodCount, ref lodCoord);
                var leafKey = leaf.PackId64();
                if (args.Leaves.ContainsKey(leafKey))
                {
                    args.Leaves.Remove(leafKey);
                    var childBase = lodCoord << 1;
                    Vector3I childOffset;
                    MyCellCoord child = new MyCellCoord();
                    child.Lod = leaf.Lod - 1;
                    var leafSize = LeafSizeInVoxels << child.Lod;
                    for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i)
                    {
                        ComputeChildCoord(i, out childOffset);
                        child.CoordInLod = childBase + childOffset;
                        var childCopy = child;
                        childCopy.Lod += LeafLodCount;
                        IMyOctreeLeafNode octreeLeaf = new MyProviderLeaf(args.Provider, args.DataType, ref childCopy);
                        args.Leaves.Add(child.PackId64(), octreeLeaf);
                        node.SetChild(i, true);
                        node.SetData(i, octreeLeaf.GetFilteredValue());
                    }
                }
                else
                {
                    leaf.Lod -= 1; // changes to node coord instead of leaf coord
                    var nodeKey = leaf.PackId64();

                    if (!args.Nodes.TryGetValue(nodeKey, out node))
                    {
                        for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i)
                            node.SetData(i, defaultData);
                    }
                }
            }

            if (lodIdx == (LeafLodCount + 1))
            {
                MyCellCoord child = new MyCellCoord();
                Vector3I childBase = lodCoord << 1;
                Vector3I minInLod = min >> LeafLodCount;
                Vector3I maxInLod = max >> LeafLodCount;
                Vector3I leafSizeMinusOne = new Vector3I(LeafSizeInVoxels - 1);
                Vector3I childOffset;
                for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i)
                {
                    ComputeChildCoord(i, out childOffset);
                    child.CoordInLod = childBase + childOffset;
                    if (!child.CoordInLod.IsInsideInclusive(ref minInLod, ref maxInLod))
                        continue;
                    var childMin = child.CoordInLod << LeafLodCount;
                    var childMax = childMin + LeafSizeInVoxels - 1;
                    Vector3I.Max(ref childMin, ref min, out childMin);
                    Vector3I.Min(ref childMax, ref max, out childMax);
                    var readOffset = childMin - min;
                    IMyOctreeLeafNode leaf;
                    var leafKey = child.PackId64();
                    var startInChild = childMin - (child.CoordInLod << LeafLodCount);
                    var endInChild = childMax - (child.CoordInLod << LeafLodCount);

                    args.Leaves.TryGetValue(leafKey, out leaf);

                    byte uniformValue;
                    bool uniformLeaf;
                    {
                        // ensure leaf exists and is writable
                        // the only writable leaf type is MicroOctree at this point

                        byte childDefaultData = node.GetData(i);

                        if (leaf == null)
                        {
                            var octree = new MyMicroOctreeLeaf(args.DataType, LeafLodCount, child.CoordInLod << (child.Lod + LeafLodCount));
                            octree.BuildFrom(childDefaultData);
                            leaf = octree;
                        }

                        if (leaf.ReadOnly)
                        {
                            var rangeEnd = new Vector3I(LeafSizeInVoxels - 1);
                            m_temporaryCache.Resize(Vector3I.Zero, rangeEnd);
                            leaf.ReadRange(m_temporaryCache, ref Vector3I.Zero, 0, ref Vector3I.Zero, ref rangeEnd);
                            var inCell = startInChild;
                            for (var it2 = new Vector3I.RangeIterator(ref startInChild, ref endInChild);
                                it2.IsValid(); it2.GetNext(out inCell))
                            {
                                var read = readOffset + (inCell - startInChild);
                                m_temporaryCache.Set(args.DataType, ref inCell, args.Source.Get(args.DataType, ref read));
                            }

                            var octree = new MyMicroOctreeLeaf(args.DataType, LeafLodCount, child.CoordInLod << (child.Lod + LeafLodCount));
                            octree.BuildFrom(m_temporaryCache);
                            leaf = octree;
                        }
                        else
                        {
                            leaf.WriteRange(args.Source, ref readOffset, ref startInChild, ref endInChild);
                        }

                        uniformLeaf = ((MyMicroOctreeLeaf)leaf).TryGetUniformValue(out uniformValue);
                    }

                    if (!uniformLeaf)
                    {
                        args.Leaves[leafKey] = leaf;
                        node.SetChild(i, true);
                    }
                    else
                    {
                        args.Leaves.Remove(leafKey);
                        node.SetChild(i, false);
                    }

                    node.SetData(i, leaf.GetFilteredValue());
                }
                args.Nodes[new MyCellCoord(lodIdx - 1 - LeafLodCount, ref lodCoord).PackId64()] = node;
            }
            else
            {
                MyCellCoord child = new MyCellCoord();
                child.Lod = lodIdx - 2 - LeafLodCount;
                var childBase = lodCoord << 1;
                Vector3I childOffset;
                var minInChild = (min >> (lodIdx-1)) - childBase;
                var maxInChild = (max >> (lodIdx-1)) - childBase;
                for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i)
                {
                    ComputeChildCoord(i, out childOffset);
                    if (!childOffset.IsInsideInclusive(ref minInChild, ref maxInChild))
                        continue;

                    child.CoordInLod = childBase + childOffset;
                    WriteRange(ref args, node.GetData(i), lodIdx - 1, child.CoordInLod, ref min, ref max);
                    var childKey = child.PackId64();
                    var childNode = args.Nodes[childKey];
                    if (!childNode.HasChildren && childNode.AllDataSame())
                    {
                        node.SetChild(i, false);
                        node.SetData(i, childNode.GetData(0));
                        args.Nodes.Remove(childKey);
                    }
                    else
                    {
                        node.SetChild(i, true);
                        node.SetData(i, childNode.ComputeFilteredValue(args.DataFilter));
                    }
                }

                args.Nodes[new MyCellCoord(lodIdx - 1 - LeafLodCount, ref lodCoord).PackId64()] = node;
            }
        }
コード例 #20
0
            /// <summary>
            /// Recursive clipping function requests cells in provided range and
            /// cells needed from parent to wrap the lod safely
            /// </summary>
            /// <param name="collector"></param>
            /// <param name="it0">requested range</param>
            /// <param name="ignore">inner range filled by children</param>
            private void DoClipping(RequestCollector collector, Vector3I min, Vector3I max, ref BoundingBox ignore)
            {
                LodLevel parentLod, clevel;

                GetNearbyLodLevels(out parentLod, out clevel);
                MyCellCoord cell = new MyCellCoord(m_lodIndex, Vector3I.Zero);

                //if (collector.SentRequestsEmpty)
                {
                    MyUtils.Swap(ref m_storedCellData, ref m_clippedCells);
                    m_storedCellData.Clear();
                }

                var it0 = new Vector3I.RangeIterator(ref min, ref max);

                cell.CoordInLod = it0.Current;

                var shiftToParent = MyVoxelCoordSystems.RenderCellSizeShiftToLessDetailed(cell.Lod);
                var parentCell    = parentLod != null ? new MyCellCoord(parentLod.m_lodIndex, cell.CoordInLod >> shiftToParent) : cell;
                var parentIgnore  = new BoundingBox(parentCell.CoordInLod, parentCell.CoordInLod);

                BoundingBox bb = new BoundingBox(cell.CoordInLod, cell.CoordInLod);

                for (; it0.IsValid(); it0.GetNext(out cell.CoordInLod)) //cells to be loaded
                {
                    if (ignore.Contains((Vector3)cell.CoordInLod) == ContainmentType.Contains)
                    {
                        continue; //lower lod requested
                    }

                    if (parentLod != null) //get also their lodcell mates
                    {
                        parentCell = new MyCellCoord(parentLod.m_lodIndex, cell.CoordInLod >> shiftToParent);
                        var it = GetChildrenCoords(this, ref parentCell);
                        bb.Include(it);
                        parentIgnore.Max = parentCell.CoordInLod;
                    }
                }
                if (parentLod != null)
                {
                    Vector3I parentMinI = Vector3I.Round(parentIgnore.Min - Vector3.One);
                    Vector3I parentMaxI = Vector3I.Round(parentIgnore.Max + Vector3.One);
                    //Vector3I.Clamp(ref parentMinI, ref Vector3I.Zero, ref m_lodSizeMinusOne, out parentMinI);
                    //Vector3I.Clamp(ref parentMaxI, ref Vector3I.Zero, ref m_lodSizeMinusOne, out parentMaxI);
                    var parentIterator = new Vector3I.RangeIterator(ref parentMinI, ref parentMaxI);
                    parentLod.DoClipping(collector, parentMinI, parentMaxI, ref parentIgnore);
                }

                Vector3I start, end;

                start = Vector3I.Round(bb.Min); end = Vector3I.Round(bb.Max);
                Vector3I.Clamp(ref start, ref Vector3I.Zero, ref m_lodSizeMinusOne, out start);
                Vector3I.Clamp(ref end, ref Vector3I.Zero, ref m_lodSizeMinusOne, out end);
                it0             = new Vector3I.RangeIterator(ref start, ref end);
                cell.CoordInLod = it0.Current;
                for (; it0.IsValid(); it0.GetNext(out cell.CoordInLod)) //cells to be loaded
                {
                    if (ignore.Contains((Vector3)cell.CoordInLod) == ContainmentType.Contains)
                    {
                        continue; //lower lod requested
                    }

                    var cellId = cell.PackId64();

                    CellData data;
                    if (m_clippedCells.TryGetValue(cellId, out data))
                    {
                        m_clippedCells.Remove(cellId);
                    }
                    else
                    {
                        var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId);

                        data = CellsCache.Read(clipmapCellId);

                        if (data == null) //cache miss
                        {
                            data = new CellData();
                            ClippingCacheMisses++;
                        }
                        else
                        {
                            //cache hit
                            ClippingCacheHits++;

                            data.InScene = false;
                            if (data.Cell != null)
                            {
                                m_nonEmptyCells[cellId] = data;
                            }
                        }
                    }

                    if (data.State == CellState.Invalid)
                    {
                        if (!TryAddCellRequest(collector, parentLod, cell, cellId, data))
                        {
                            continue;
                        }
                    }
                    if (!m_storedCellData.ContainsKey(cellId))
                    {
                        m_storedCellData.Add(cellId, data);
                    }
                }
            }
コード例 #21
0
            internal void DoClipping_Old(Vector3D localPosition, float farPlaneDistance, RequestCollector collector)
            {
                m_localPosition = localPosition;
                MyClipmap.ComputeLodViewBounds(m_clipmap.m_scaleGroup, m_lodIndex, out m_nearDistance, out m_farDistance);

                m_fitsInFrustum = (farPlaneDistance * 1.25f) > m_nearDistance;

                if (!m_fitsInFrustum)
                {
                    return;
                }


                //var localFrustum = new BoundingFrustumD(CameraFrustumGetter().Matrix * m_parent.m_invWorldMatrix);
                var frustum = CameraFrustumGetter();

                Vector3I min, max;
                Vector3I ignoreMin, ignoreMax;

                var minD = m_localPosition - m_farDistance;
                var maxD = m_localPosition + m_farDistance;

                MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref minD, out min);
                MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref maxD, out max);

                BoundingBoxI lodBox         = new BoundingBoxI(Vector3I.Zero, m_lodSizeMinusOne);
                bool         intersects     = false;
                bool         intersectsNear = false;

                m_localFarCameraBox  = new BoundingBoxI(min, max);
                m_localNearCameraBox = new BoundingBoxI(min, max);
                if (lodBox.Intersects(m_localFarCameraBox))
                {
                    intersects = true;
                    var intersection = lodBox.Intersect(m_localFarCameraBox);
                    min = intersection.Min;
                    max = intersection.Max;

                    //Optimize only LOD2 and higher by two lods, because neighbour cells shares border cells
                    if (m_lodIndex > 1)
                    {
                        float lowerFar, lowerNear;
                        MyClipmap.ComputeLodViewBounds(m_clipmap.m_scaleGroup, m_lodIndex - 2, out lowerFar, out lowerNear);

                        var minNear = m_localPosition - (lowerNear - MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex) / 2);
                        var maxNear = m_localPosition + (lowerNear - MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex) / 2);
                        MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref minNear, out ignoreMin);
                        MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref maxNear, out ignoreMax);

                        m_localNearCameraBox = new BoundingBoxI(ignoreMin, ignoreMax);
                        if (lodBox.Intersects(m_localNearCameraBox))
                        {
                            intersectsNear = false;
                        }
                    }
                }

                if (m_lastMin == min && m_lastMax == max && !m_clipmap.m_updateClipping)
                {
                    return;
                }

                m_lastMin = min;
                m_lastMax = max;

                LodLevel parentLod, childLod;

                GetNearbyLodLevels(out parentLod, out childLod);

                // Moves cells which are still needed from one collection to another.
                // All that is left behind is unloaded as no longer needed.

                // Move everything in range to collection of next stored cells.
                MyUtils.Swap(ref m_storedCellData, ref m_clippedCells);
                m_storedCellData.Clear();

                if (intersects)
                {
                    float sizeInMetres = MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex);

                    MyCellCoord cell = new MyCellCoord(m_lodIndex, ref min);
                    for (var it = new Vector3I.RangeIterator(ref min, ref max);
                         it.IsValid(); it.GetNext(out cell.CoordInLod))
                    {
                        if (intersectsNear &&
                            m_localNearCameraBox.Contains(cell.CoordInLod) == ContainmentType.Contains)
                        {
                            continue;
                        }

                        //if (!WasAncestorCellLoaded(parentLod, ref cell))
                        //    continue;


                        Vector3D minAABB = Vector3D.Transform((Vector3D)(sizeInMetres * (cell.CoordInLod - 2)), m_clipmap.m_worldMatrix);
                        Vector3D maxAABB = Vector3D.Transform((Vector3D)(sizeInMetres * (cell.CoordInLod + 2) + new Vector3(sizeInMetres)), m_clipmap.m_worldMatrix);

                        if (frustum.Contains(new BoundingBoxD(minAABB, maxAABB)) == ContainmentType.Disjoint)
                        {
                            continue;
                        }

                        var      cellId = cell.PackId64();
                        CellData data;
                        if (m_clippedCells.TryGetValue(cellId, out data))
                        {
                            m_clippedCells.Remove(cellId);
                        }
                        else
                        {
                            var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId);
                            data = CellsCache.Read(clipmapCellId);

                            if (data == null) //cache miss
                            {
                                data = new CellData();
                                ClippingCacheMisses++;
                            }
                            else
                            {
                                //cache hit
                                ClippingCacheHits++;

                                //System.Diagnostics.Debug.Assert((!data.InScene && data.Cell != null) || data.Cell == null, "Not allowed cell state");
                                data.InScene = false;
                                if (data.Cell != null)
                                {
                                    m_nonEmptyCells[cellId] = data;
                                }
                            }
                        }

                        if (data.State == CellState.Invalid)
                        {
                            if (!TryAddCellRequest(collector, parentLod, cell, cellId, data))
                            {
                                continue;
                            }
                        }
                        m_storedCellData.Add(cellId, data);
                    }
                }
            }
コード例 #22
0
        public void ProcessChangedCellComponents()
        {
            ProfilerShort.Begin("ProcessChangedCellComponents");

            m_currentHelper = this;

            Vector3I min, max, pos;
            List<int> triangles = null;
            foreach (var cell in m_changedCells)
            {
                min = CellToLowestCube(cell);
                max = min + m_cellSize - Vector3I.One;

                // Save a hashset of all the triangles in the current cell
                pos = min;
                for (var it = new Vector3I_RangeIterator(ref min, ref max); it.IsValid(); it.GetNext(out pos))
                {
                    if (!m_triangleRegistry.TryGetValue(pos, out triangles)) continue;

                    foreach (var triIndex in triangles)
                    {
                        m_tmpCellTriangles.Add(triIndex);
                    }
                }

                if (m_tmpCellTriangles.Count == 0) continue;

                MyCellCoord cellCoord = new MyCellCoord(0, cell);
                ulong packedCell = cellCoord.PackId64();
                m_components.OpenCell(packedCell);

                long timeBegin = m_mesh.GetCurrentTimestamp() + 1;
                long timeEnd = timeBegin;
                m_currentComponentRel = 0;

                m_tmpComponentTriangles.Clear();
                foreach (var triIndex in m_tmpCellTriangles)
                {
                    // Skip already visited triangles
                    var triangle = m_mesh.GetTriangle(triIndex);
                    if (m_currentComponentRel != 0 && m_mesh.VisitedBetween(triangle, timeBegin, timeEnd)) continue;

                    m_components.OpenComponent();

                    // Make sure we have place in m_currentCellConnections
                    if (m_currentComponentRel >= m_currentCellConnections.Count)
                    {
                        m_currentCellConnections.Add(new List<int>());
                    }

                    // Find connected component from an unvisited triangle and mark its connections
                    m_components.AddComponentTriangle(triangle, triangle.Center);
                    triangle.ComponentIndex = m_currentComponentRel;
                    m_tmpComponentTriangles.Add(triangle);
                    m_mesh.PrepareTraversal(triangle, null, m_processTrianglePredicate);
                    m_mesh.PerformTraversal();
                    m_tmpComponentTriangles.Add(null);

                    m_components.CloseComponent();

                    timeEnd = m_mesh.GetCurrentTimestamp();
                    if (m_currentComponentRel == 0)
                    {
                        timeBegin = timeEnd;
                    }
                    m_currentComponentRel++;
                }

                m_tmpCellTriangles.Clear();

                MyNavmeshComponents.ClosedCellInfo cellInfo = new MyNavmeshComponents.ClosedCellInfo();
                m_components.CloseAndCacheCell(ref cellInfo);

                // Renumber triangles from the old indices to the newly assigned index from m_components
                int componentIndex = cellInfo.StartingIndex;
                foreach (var triangle in m_tmpComponentTriangles)
                {
                    if (triangle == null)
                    {
                        componentIndex++;
                        continue;
                    }
                    triangle.ComponentIndex = componentIndex;
                }
                m_tmpComponentTriangles.Clear();

                // Remove old component primitives
                if (!cellInfo.NewCell && cellInfo.ComponentNum != cellInfo.OldComponentNum)
                {
                    for (int i = 0; i < cellInfo.OldComponentNum; ++i)
                    {
                        m_mesh.HighLevelGroup.RemovePrimitive(cellInfo.OldStartingIndex + i);
                    }
                }

                // Add new component primitives
                if (cellInfo.NewCell || cellInfo.ComponentNum != cellInfo.OldComponentNum)
                {
                    for (int i = 0; i < cellInfo.ComponentNum; ++i)
                    {
                        m_mesh.HighLevelGroup.AddPrimitive(cellInfo.StartingIndex + i, m_components.GetComponentCenter(i));
                    }
                }

                // Update existing component primitives
                if (!cellInfo.NewCell && cellInfo.ComponentNum == cellInfo.OldComponentNum)
                {
                    for (int i = 0; i < cellInfo.ComponentNum; ++i)
                    {
                        var primitive = m_mesh.HighLevelGroup.GetPrimitive(cellInfo.StartingIndex + i);
                        primitive.UpdatePosition(m_components.GetComponentCenter(i));
                    }
                }

                // Connect new components with the others in the neighboring cells
                for (int i = 0; i < cellInfo.ComponentNum; ++i)
                {
                    int compIndex = cellInfo.StartingIndex + i;

                    var primitive = m_mesh.HighLevelGroup.GetPrimitive(compIndex);
                    primitive.GetNeighbours(m_tmpNeighbors);

                    // Connect to disconnected components
                    foreach (var connection in m_currentCellConnections[i])
                    {
                        if (!m_tmpNeighbors.Remove(connection))
                        {
                            m_mesh.HighLevelGroup.ConnectPrimitives(compIndex, connection);
                        }
                    }

                    // Disconnect neighbors that should be no longer connected
                    foreach (var neighbor in m_tmpNeighbors)
                    {
                        // Only disconnect from the other cell if it is expanded and there was no connection found
                        var neighborPrimitive = m_mesh.HighLevelGroup.TryGetPrimitive(neighbor);
                        if (neighborPrimitive != null && neighborPrimitive.IsExpanded)
                        {
                            m_mesh.HighLevelGroup.DisconnectPrimitives(compIndex, neighbor);
                        }
                    }

                    m_tmpNeighbors.Clear();
                    m_currentCellConnections[i].Clear();
                }

                // Set all the components as expanded
                for (int i = 0; i < cellInfo.ComponentNum; ++i)
                {
                    componentIndex = cellInfo.StartingIndex + i;
                    var component = m_mesh.HighLevelGroup.GetPrimitive(componentIndex);
                    if (component != null)
                    {
                        component.IsExpanded = true;
                    }
                }
            }

            m_changedCells.Clear();

            m_currentHelper = null;

            ProfilerShort.End();
        }
コード例 #23
0
        public void ProcessCellComponents()
        {
            ProfilerShort.Begin("ProcessCellComponents");
            m_triangleLists.Add(m_packedCoord, m_triangleList.GetCopy());

            long timeBegin = m_mesh.GetCurrentTimestamp() + 1;
            long timeEnd = timeBegin;

            m_currentComponentRel = 0;
            m_currentComponent = m_navmeshComponents.OpenCell(m_packedCoord);

            foreach (var triIndex in m_triangleList)
            {
                // Skip already visited triangles
                var triangle = m_mesh.GetTriangle(triIndex);
                if (m_mesh.VisitedBetween(triangle, timeBegin, timeEnd))
                {
                    continue;
                }

                m_navmeshComponents.OpenComponent();

                // Make sure we have place in m_currentCellConnections
                if (m_currentComponentRel >= m_currentCellConnections.Count)
                {
                    m_currentCellConnections.Add(new List<ConnectionInfo>());
                }

                // Find connected component from an unvisited triangle
                ProfilerShort.Begin("Graph traversal");
                m_currentHelper = this;

                m_navmeshComponents.AddComponentTriangle(triangle, triangle.Center);
                triangle.ComponentIndex = m_navmeshComponents.OpenComponentIndex;
                m_mesh.PrepareTraversal(triangle, null, m_processTrianglePredicate);

                var primitiveEnum = m_mesh.GetEnumerator();
                while (primitiveEnum.MoveNext());
                primitiveEnum.Dispose();
                ProfilerShort.End();

                m_navmeshComponents.CloseComponent();

                timeEnd = m_mesh.GetCurrentTimestamp();
                m_currentComponentRel++;
            }

            MyNavmeshComponents.ClosedCellInfo cellInfo = new MyNavmeshComponents.ClosedCellInfo();
            m_navmeshComponents.CloseAndCacheCell(ref cellInfo);

            // Add new component primitives 
            if (cellInfo.NewCell)
            {
                for (int i = 0; i < cellInfo.ComponentNum; ++i)
                {
                    m_mesh.HighLevelGroup.AddPrimitive(cellInfo.StartingIndex + i, m_navmeshComponents.GetComponentCenter(i));
                }
            }
            
            // Connect new components with the others in the neighboring cells
            for (int i = 0; i < cellInfo.ComponentNum; ++i)
            {
                foreach (var connectionInfo in m_currentCellConnections[i])
                {
                    if (!cellInfo.ExploredDirections.HasFlag(Base6Directions.GetDirectionFlag(connectionInfo.Direction)))
                    {
                        m_mesh.HighLevelGroup.ConnectPrimitives(cellInfo.StartingIndex + i, connectionInfo.ComponentIndex);
                    }
                }
                m_currentCellConnections[i].Clear();
            }

            // Mark explored directions in the navmesh component helper
            foreach (var direction in Base6Directions.EnumDirections)
            {
                var dirFlag = Base6Directions.GetDirectionFlag(direction);
                if (cellInfo.ExploredDirections.HasFlag(dirFlag))
                {
                    continue;
                }

                Vector3I dirVec = Base6Directions.GetIntVector(direction);

                MyCellCoord otherCoord = new MyCellCoord();
                otherCoord.Lod = MyVoxelNavigationMesh.NAVMESH_LOD;
                otherCoord.CoordInLod = m_currentCell + dirVec;
                if (otherCoord.CoordInLod.X == -1 || otherCoord.CoordInLod.Y == -1 || otherCoord.CoordInLod.Z == -1)
                {
                    continue;
                }

                ulong otherPackedCoord = otherCoord.PackId64();

                if (m_triangleLists.ContainsKey(otherPackedCoord))
                {
                    m_navmeshComponents.MarkExplored(otherPackedCoord, Base6Directions.GetFlippedDirection(direction));
                    cellInfo.ExploredDirections |= Base6Directions.GetDirectionFlag(direction);
                }
            }
            m_navmeshComponents.SetExplored(m_packedCoord, cellInfo.ExploredDirections);

            // Set all the components as expanded
            for (int i = 0; i < cellInfo.ComponentNum; ++i)
            {
                int componentIndex = cellInfo.StartingIndex + i;
                var component = m_mesh.HighLevelGroup.GetPrimitive(componentIndex);
                if (component != null)
                {
                    component.IsExpanded = true;
                }
            }

            ProfilerShort.End();
        }
コード例 #24
0
 internal void OnCellRequestCancelled(MyCellCoord cell)
 {
     var workId = cell.PackId64();
     m_renderWorkTracker.Cancel(workId);
 }
コード例 #25
0
        public void TryClearCell(ulong packedCoord)
        {
            if (m_triangleLists.ContainsKey(packedCoord))
            {
                ClearCachedCell(packedCoord);
            }

            RemoveExplored(packedCoord);

            MyNavmeshComponents.CellInfo cellInfo;
            if (!m_navmeshComponents.TryGetCell(packedCoord, out cellInfo))
            {
                return;
            }

            for (int i = 0; i < cellInfo.ComponentNum; ++i)
            {
                int componentIndex = cellInfo.StartingIndex + i;
                m_mesh.HighLevelGroup.RemovePrimitive(componentIndex);
            }

            foreach (var direction in Base6Directions.EnumDirections)
            {
                Base6Directions.DirectionFlags dirFlag = Base6Directions.GetDirectionFlag(direction);
                if (cellInfo.ExploredDirections.HasFlag(dirFlag))
                {
                    Vector3I dirVec = Base6Directions.GetIntVector(direction);

                    MyCellCoord otherCoord = new MyCellCoord();
                    otherCoord.SetUnpack(packedCoord);
                    Debug.Assert(otherCoord.Lod == MyVoxelNavigationMesh.NAVMESH_LOD);
                    otherCoord.CoordInLod = otherCoord.CoordInLod + dirVec;

                    MyNavmeshComponents.CellInfo otherCellInfo;

                    if (m_navmeshComponents.TryGetCell(otherCoord.PackId64(), out otherCellInfo))
                    {
                        Base6Directions.DirectionFlags flippedFlag = Base6Directions.GetDirectionFlag(Base6Directions.GetFlippedDirection(direction));
                        m_navmeshComponents.SetExplored(otherCoord.PackId64(), otherCellInfo.ExploredDirections & ~flippedFlag);
                    }
                    else
                    {
                        Debug.Assert(false, "Could not get the oposite explored cell!");
                    }
                }
            }

            m_navmeshComponents.ClearCell(packedCoord, ref cellInfo);
        }
コード例 #26
0
        private bool TryGetCell(MyCellCoord cell, out bool isEmpty, out CellData nonEmptyCell)
        {
            MyPrecalcComponent.AssertUpdateThread();
            using (m_lock.AcquireSharedUsing())
            {
                if (IsEmpty(ref cell))
                {
                    isEmpty = true;
                    nonEmptyCell = null;
                    return true;
                }

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

                isEmpty = default(bool);
                nonEmptyCell = default(CellData);
                return false;
            }
        }
コード例 #27
0
        /// <summary>
        /// Begins processing a voxel geometry cell
        /// </summary>
        public void OpenNewCell(MyCellCoord coord)
        {
            Debug.Assert(m_cellOpen == false, "Cannot open a new cell in MyVoxelHighLevelHelper while another one is open!");

            m_cellOpen = true;
            m_currentCell = coord.CoordInLod;
            m_packedCoord = coord.PackId64();
            m_triangleList.Clear();
        }
コード例 #28
0
        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);
                }
            }
        }
コード例 #29
0
            internal void DoClipping(Vector3D localPosition, float farPlaneDistance, RequestCollector collector)
            {
                MyClipmap.ComputeLodViewBounds(m_parent.m_scaleGroup, m_lodIndex, out m_nearDistance, out m_farDistance);

                m_fitsInFrustum = (farPlaneDistance * 1.25f) > m_nearDistance;

                if (!m_fitsInFrustum)
                    return;

                Vector3I min, max;
                {
                    var minD = localPosition - m_farDistance;
                    var maxD = localPosition + m_farDistance;
                    MyVoxelCoordSystems.LocalPositionToRenderCellCoord(ref minD, out min);
                    MyVoxelCoordSystems.LocalPositionToRenderCellCoord(ref maxD, out max);
                    Vector3I.Max(ref min, ref Vector3I.Zero, out min);
                    Vector3I.Max(ref max, ref Vector3I.Zero, out max);
                    min >>= m_lodIndex;
                    max >>= m_lodIndex;

                    Vector3I.Min(ref min, ref m_lodSizeMinusOne, out min);
                    Vector3I.Min(ref max, ref m_lodSizeMinusOne, out max);
                }

                if (m_lastMin == min && m_lastMax == max && !m_parent.m_updateClipping)
                    return;

                m_lastMin = min;
                m_lastMax = max;

                LodLevel parentLod, childLod;
                GetNearbyLodLevels(out parentLod, out childLod);

                // Moves cells which are still needed from one collection to another.
                // All that is left behind is unloaded as no longer needed.

                // Move everything in range to collection of next stored cells.
                MyUtils.Swap(ref m_storedCellData, ref m_clippedCells);
                m_storedCellData.Clear();
                MyCellCoord cell = new MyCellCoord(m_lodIndex, ref min);
                for (var it = new Vector3I.RangeIterator(ref min, ref max);
                    it.IsValid(); it.GetNext(out cell.CoordInLod))
                {
                    if (!WasAncestorCellLoaded(parentLod, ref cell))
                        continue;

                    var cellId = cell.PackId64();
                    CellData data;
                    if (m_clippedCells.TryGetValue(cellId, out data))
                        m_clippedCells.Remove(cellId);
                    else
                        data = new CellData();

                    if (data.State == CellState.Invalid)
                    {
                        collector.AddRequest(cellId, data.WasLoaded);
                        data.State = CellState.Pending;
                    }
                    m_storedCellData.Add(cellId, data);
                }
            }
コード例 #30
0
        internal CellData GetCell(ref MyCellCoord cell)
        {
            MyPrecalcComponent.AssertUpdateThread();

            bool isEmpty;
            CellData data;
            if (TryGetCell(cell, out isEmpty, out data))
            {
                return data;
            }

            MyIsoMesh mesh;
            if (!TryGetMesh(cell, out isEmpty, out mesh))
            {
                ProfilerShort.Begin("Cell precalc");
                if (true)
                {
                    var min = cell.CoordInLod << MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS;
                    var max = min + MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS;
                    // overlap to neighbor; introduces extra data but it makes logic for raycasts simpler (no need to check neighbor cells)
                    min -= 1;
                    max += 2;
                    mesh = MyPrecalcComponent.IsoMesher.Precalc(m_storage, 0, min, max, false, MyFakes.ENABLE_VOXEL_COMPUTED_OCCLUSION, true);
                }
                else
                {
                    mesh = MyPrecalcComponent.IsoMesher.Precalc(new MyIsoMesherArgs()
                    {
                        Storage = m_storage,
                        GeometryCell = cell,
                    });
                }
                ProfilerShort.End();
            }

            if (mesh != null)
            {
                data = new CellData();
                data.Init(
                    mesh.PositionOffset, mesh.PositionScale,
                    mesh.Positions.GetInternalArray(), mesh.VerticesCount,
                    mesh.Triangles.GetInternalArray(), mesh.TrianglesCount);
            }

            if (cell.Lod == 0)
            {
                using (m_lock.AcquireExclusiveUsing())
                {
                    if (data != null)
                    {
                        var key = cell.PackId64();
                        m_cellsByCoordinate[key] = data;
                    }
                    else
                    {
                        SetEmpty(ref cell, true);
                    }
                }
            }

            return data;
        }
コード例 #31
0
            /// <summary>
            /// Checks ancestor nodes recursively. Typically, this checks at most 9 nodes or so (depending on settings).
            /// </summary>
            private static bool WasAncestorCellLoaded(LodLevel parentLod, ref MyCellCoord thisLodCell)
            {            
                if (parentLod == null || !parentLod.m_fitsInFrustum || !parentLod.Visible)
                {
                    return true;
                }

                Debug.Assert(thisLodCell.Lod == parentLod.m_lodIndex - 1);

                var parentCell = new MyCellCoord(thisLodCell.Lod + 1, thisLodCell.CoordInLod >> 1);
                CellData data;
                if (parentLod.m_storedCellData.TryGetValue(parentCell.PackId64(), out data))
                {
                    return data.WasLoaded;
                }

                LodLevel ancestor;
                if (parentLod.m_parent.m_lodLevels.TryGetValue(parentLod.m_lodIndex+1, out ancestor))
                    return WasAncestorCellLoaded(ancestor, ref parentCell);
                else
                    return false;
            }
コード例 #32
0
        public void InvalidateRange(Vector3I minVoxelChanged, Vector3I maxVoxelChanged)
        {
            minVoxelChanged -= MyPrecalcComponent.InvalidatedRangeInflate;
            maxVoxelChanged += MyPrecalcComponent.InvalidatedRangeInflate;

            m_voxelMap.Storage.ClampVoxelCoord(ref minVoxelChanged);
            m_voxelMap.Storage.ClampVoxelCoord(ref maxVoxelChanged);

            Vector3I minCell, maxCell;
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref minVoxelChanged, out minCell);
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxVoxelChanged, out maxCell);

            Vector3I currentCell = minCell;
            for (var it = new Vector3I.RangeIterator(ref minCell, ref maxCell); it.IsValid(); it.GetNext(out currentCell))
            {
                if (m_processedCells.Contains(ref currentCell))
                {
                    RemoveCell(currentCell);
                }

                MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, currentCell);
                m_higherLevelHelper.TryClearCell(coord.PackId64());
            }
        }
コード例 #33
0
            /// <summary>
            /// Checks only immediate children (any deeper would take too long).
            /// </summary>
            private static bool ChildrenWereLoaded(LodLevel childLod, ref MyCellCoord thisLodCell)
            {
                if (childLod == null || !childLod.Visible)
                    return false;

                Debug.Assert(thisLodCell.Lod == childLod.m_lodIndex + 1);

                var childLodCell = new MyCellCoord();
                childLodCell.Lod = childLod.m_lodIndex;
                var start = thisLodCell.CoordInLod << 1;
                var end = start + 1;

                Vector3I.Min(ref end, ref childLod.m_lodSizeMinusOne, out end);
                for (childLodCell.CoordInLod.Z = start.Z; childLodCell.CoordInLod.Z <= end.Z; ++childLodCell.CoordInLod.Z)
                for (childLodCell.CoordInLod.Y = start.Y; childLodCell.CoordInLod.Y <= end.Y; ++childLodCell.CoordInLod.Y)
                for (childLodCell.CoordInLod.X = start.X; childLodCell.CoordInLod.X <= end.X; ++childLodCell.CoordInLod.X)
                {
                    var key = childLodCell.PackId64();
                    CellData data;
                    if (!childLod.m_storedCellData.TryGetValue(key, out data))
                    {
                        return false;
                    }

                    if (!data.WasLoaded)
                    {
                        return false;
                    }
                }

                return true;
            }
コード例 #34
0
        private bool RemoveCell(Vector3I cell)
        {
            if (!MyFakes.REMOVE_VOXEL_NAVMESH_CELLS) return true;

            Debug.Assert(m_processedCells.Contains(cell), "Removing a non-existent cell from the navmesh!");
            if (!m_processedCells.Contains(cell)) return false;

            MyTrace.Send(TraceWindow.Ai, "Removing cell " + cell);

            ProfilerShort.Begin("Removing navmesh links");
            MyVoxelPathfinding.CellId cellId = new MyVoxelPathfinding.CellId() { VoxelMap = m_voxelMap, Pos = cell };
            m_navmeshCoordinator.RemoveVoxelNavmeshLinks(cellId);
            ProfilerShort.End();

            ProfilerShort.Begin("Removing triangles");
            MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, cell);
            ulong packedCoord = coord.PackId64();
            MyIntervalList triangleList = m_higherLevelHelper.TryGetTriangleList(packedCoord);
            if (triangleList != null)
            {
                foreach (var triangleIndex in triangleList)
                {
                    RemoveTerrainTriangle(GetTriangle(triangleIndex));
                }
                m_higherLevelHelper.ClearCachedCell(packedCoord);
            }
            ProfilerShort.End();

            Debug.Assert(m_processedCells.Contains(ref cell));
            m_processedCells.Remove(ref cell);

            return triangleList != null;
        }
コード例 #35
0
        protected override void ResetInternal(MyStorageDataTypeFlags dataToReset)
        {
            bool resetContent = (dataToReset & MyStorageDataTypeFlags.Content) != 0;
            bool resetMaterials = (dataToReset & MyStorageDataTypeFlags.Material) != 0;

            if (resetContent)
            {
                m_contentLeaves.Clear();
                m_contentNodes.Clear();
            }

            if (resetMaterials)
            {
                m_materialLeaves.Clear();
                m_materialNodes.Clear();
            }

            if (m_dataProvider != null)
            {
                var cellCoord = new MyCellCoord(m_treeHeight, ref Vector3I.Zero);
                var leafId = cellCoord.PackId64();
                cellCoord.Lod += LeafLodCount;
                var end = Size - 1;
                if (resetContent)
                {
                    m_contentLeaves.Add(leafId,
                        new MyProviderLeaf(m_dataProvider, MyStorageDataTypeEnum.Content, ref cellCoord));
                }
                if (resetMaterials)
                {
                    m_materialLeaves.Add(leafId,
                        new MyProviderLeaf(m_dataProvider, MyStorageDataTypeEnum.Material, ref cellCoord));
                }
            }
            else
            {
                var nodeId = new MyCellCoord(m_treeHeight - 1, ref Vector3I.Zero).PackId64();
                if (resetContent)
                {
                    m_contentNodes.Add(nodeId, new MyOctreeNode());
                }
                if (resetMaterials)
                {
                    m_materialNodes.Add(nodeId, new MyOctreeNode());
                }
            }
        }
コード例 #36
0
        private MyHighLevelPrimitive GetClosestHighLevelPrimitive(ref Vector3 point, ref float closestDistanceSq)
        {
            MyHighLevelPrimitive retval = null;

            // Convert from world matrix local coords to LeftBottomCorner-based coords
            Vector3 lbcPoint = point + (m_voxelMap.PositionComp.GetPosition() - m_voxelMap.PositionLeftBottomCorner);

            m_tmpIntList.Clear();

            // Collect components from the eight closest cells
            Vector3I closestCellCorner = Vector3I.Round(lbcPoint / m_cellSize);
            for (int i = 0; i < 8; ++i)
            {
                Vector3I cell = closestCellCorner + m_cornerOffsets[i];

                MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, cell);
                ulong packedCoord = coord.PackId64();

                m_higherLevelHelper.CollectComponents(packedCoord, m_tmpIntList);
            }

            foreach (int componentIndex in m_tmpIntList)
            {
                var hlPrimitive = m_higherLevel.GetPrimitive(componentIndex);
                Debug.Assert(hlPrimitive != null, "Couldnt' find a high-level primitive for the index given by higher level helper!");
                if (hlPrimitive == null) continue;

                float distSq = Vector3.DistanceSquared(hlPrimitive.Position, point);
                if (distSq < closestDistanceSq)
                {
                    closestDistanceSq = distSq;
                    retval = hlPrimitive;
                }
            }

            m_tmpIntList.Clear();

            return retval;
        }
コード例 #37
0
        private static ulong CountChangedVoxelsAmount(
            MyOctreeStorage baseStorage,
            int lodIdx,
            Dictionary<UInt64, MyOctreeNode> nodes,
            Dictionary<UInt64, IMyOctreeLeafNode> leaves,
            Vector3I lodCoord)
        {
            var currentCell = new MyCellCoord(lodIdx, lodCoord);
            var leafKey = currentCell.PackId64();

            IMyOctreeLeafNode leaf;
            if (leaves.TryGetValue(leafKey, out leaf))
            {
                if (!leaf.ReadOnly && currentCell.Lod == 0)
                {
                    // Read data from leaf
                    var rangeEnd = new Vector3I(LeafSizeInVoxels - 1);
                    m_temporaryCache.Resize(Vector3I.Zero, rangeEnd);
                    leaf.ReadRange(m_temporaryCache, ref Vector3I.Zero, 0, ref Vector3I.Zero, ref rangeEnd);

                    // Read data from base storage
                    var minLeafVoxel = currentCell.CoordInLod * LeafSizeInVoxels;
                    var maxLeafVoxel = minLeafVoxel + (LeafSizeInVoxels - 1);
                    m_temporaryCache2.Resize(minLeafVoxel, maxLeafVoxel);
                    baseStorage.ReadRange(m_temporaryCache2, MyStorageDataTypeFlags.Content, currentCell.Lod, ref minLeafVoxel, ref maxLeafVoxel);

                    byte[] origData = m_temporaryCache2.Data;
                    byte[] currData = m_temporaryCache.Data;

                    Debug.Assert(currData.Length == origData.Length);

                    if (currData.Length != origData.Length)
                        return 0;

                    ulong countChangedVoxels = 0;
                    for (int i = (int)MyStorageDataTypeEnum.Content; i < m_temporaryCache.SizeLinear; i += m_temporaryCache.StepLinear)
                    {
                        countChangedVoxels += (ulong)Math.Abs(currData[i] - origData[i]);
                    }

                    return countChangedVoxels;
                }
            }
            else
            {
                currentCell.Lod -= 1;

                var nodeKey = currentCell.PackId64();
                var node = nodes[nodeKey];

                var childBase = lodCoord << 1;
                Vector3I childOffset;

                if (node.HasChildren)
                {
                    ulong count = 0;

                    for (int i = 0; i < MyOctreeNode.CHILD_COUNT; i++)
                    {
                        if (node.HasChild(i))
                        {
                            ComputeChildCoord(i, out childOffset);
                            currentCell.CoordInLod = childBase + childOffset;

                            count += CountChangedVoxelsAmount(baseStorage, currentCell.Lod, nodes, leaves, currentCell.CoordInLod);
                        }
                    }

                    return count;
                }
                else
                {
                    return (ulong)((MyOctreeNode.CHILD_COUNT << (currentCell.Lod * 3)) * LeafSizeInVoxels * LeafSizeInVoxels * LeafSizeInVoxels * MyVoxelConstants.VOXEL_CONTENT_FULL);
                }
            }

            return 0;
        }
コード例 #38
0
ファイル: MyClipmap.cs プロジェクト: Tyrsis/SpaceEngineers-1
            internal void DoClipping(Vector3D localPosition, float farPlaneDistance, RequestCollector collector)
            {
                MyClipmap.ComputeLodViewBounds(m_parent.m_scaleGroup, m_lodIndex, out m_nearDistance, out m_farDistance);

                m_fitsInFrustum = (farPlaneDistance * 1.25f) > m_nearDistance;

                if (!m_fitsInFrustum)
                {
                    return;
                }

                Vector3I min, max;

                {
                    var minD = localPosition - m_farDistance;
                    var maxD = localPosition + m_farDistance;
                    MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref minD, out min);
                    MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref maxD, out max);
                    Vector3I.Clamp(ref min, ref Vector3I.Zero, ref m_lodSizeMinusOne, out min);
                    Vector3I.Clamp(ref max, ref Vector3I.Zero, ref m_lodSizeMinusOne, out max);
                }

                if (m_lastMin == min && m_lastMax == max && !m_parent.m_updateClipping)
                {
                    return;
                }

                m_lastMin = min;
                m_lastMax = max;

                LodLevel parentLod, childLod;

                GetNearbyLodLevels(out parentLod, out childLod);

                // Moves cells which are still needed from one collection to another.
                // All that is left behind is unloaded as no longer needed.

                // Move everything in range to collection of next stored cells.
                MyUtils.Swap(ref m_storedCellData, ref m_clippedCells);
                m_storedCellData.Clear();
                MyCellCoord cell = new MyCellCoord(m_lodIndex, ref min);

                for (var it = new Vector3I.RangeIterator(ref min, ref max);
                     it.IsValid(); it.GetNext(out cell.CoordInLod))
                {
                    if (!WasAncestorCellLoaded(parentLod, ref cell))
                    {
                        continue;
                    }

                    var      cellId = cell.PackId64();
                    CellData data;
                    if (m_clippedCells.TryGetValue(cellId, out data))
                    {
                        m_clippedCells.Remove(cellId);
                    }
                    else
                    {
                        data = new CellData();
                    }

                    if (data.State == CellState.Invalid)
                    {
                        collector.AddRequest(cellId, data.WasLoaded);
                        data.State = CellState.Pending;
                    }
                    m_storedCellData.Add(cellId, data);
                }
            }
コード例 #39
0
        private static bool ResetOutsideBorders(
            IMyStorageDataProvider provider,
            MyStorageDataTypeEnum dataType,
            int lodIdx,
            Dictionary<UInt64, MyOctreeNode> nodes,
            Dictionary<UInt64, IMyOctreeLeafNode> leaves,
            Vector3I lodCoord,
            Vector3I minVoxel,
            Vector3I maxVoxel,
            out bool canCollapse,
            Dictionary<UInt64, IMyOctreeLeafNode> outResetLeaves = null) 
        {
            canCollapse = false;

            bool changed = false;

            var currentCell = new MyCellCoord(lodIdx, lodCoord);
            var key = currentCell.PackId64();
            var leafCell = currentCell;
            var leafKey = leafCell.PackId64();

            IMyOctreeLeafNode leaf;
            if (leaves.TryGetValue(leafKey, out leaf))
            {
                canCollapse = leaf.ReadOnly;

                if (leafCell.Lod != 0)
                {
                    Debug.Assert(leaf.ReadOnly);
                    return false;
                }
                else if (!leaf.ReadOnly)
                {
                    var minCell = minVoxel >> (LeafLodCount + leafCell.Lod);
                    var maxCell = maxVoxel >> (LeafLodCount + leafCell.Lod);

                    if (!leafCell.CoordInLod.IsInsideInclusive(ref minCell, ref maxCell))
                    {
                        canCollapse = true;

                        leaves.Remove(leafKey);
                        var leafCellCopy = leafCell;
                        leafCellCopy.Lod += LeafLodCount;
                        var leafNew = new MyProviderLeaf(provider, dataType, ref leafCellCopy);
                        leaves.Add(leafKey, leafNew);

                        changed = true;

                        if (outResetLeaves != null)
                            outResetLeaves.Add(leafKey, leafNew);
                    }
                }
            }
            else
            {
                currentCell.Lod -= 1;
                key = currentCell.PackId64();
                var nodeCell = currentCell;

                var nodeKey = currentCell.PackId64();
                var node = nodes[nodeKey];

                var childBase = lodCoord << 1;
                Vector3I childOffset;
                var minInChild = (minVoxel >> (LeafLodCount + currentCell.Lod)) - childBase;
                var maxInChild = (maxVoxel >> (LeafLodCount + currentCell.Lod)) - childBase;
                var leafSize = LeafSizeInVoxels << currentCell.Lod;

                unsafe
                {
                    canCollapse = true;

                    for (int i = 0; i < MyOctreeNode.CHILD_COUNT; i++)
                    {
                        ComputeChildCoord(i, out childOffset);
                        if (childOffset.IsInsideExclusive(ref minInChild, ref maxInChild))
                        {
                            canCollapse = false;
                            continue;
                        }

                        currentCell.CoordInLod = childBase + childOffset;

                        if (node.HasChild(i))
                        {
                            bool localCanCollapse;
                            bool resetChanged = ResetOutsideBorders(provider, dataType, currentCell.Lod, nodes, leaves, currentCell.CoordInLod, minVoxel, maxVoxel, out localCanCollapse, outResetLeaves: outResetLeaves);
                            changed = changed || resetChanged;

                            canCollapse = localCanCollapse && canCollapse;
                        }
                        else
                        {
                            var currentCellCopy = currentCell;
                            currentCellCopy.Lod += LeafLodCount;
                            IMyOctreeLeafNode octreeLeaf = new MyProviderLeaf(provider, dataType, ref currentCellCopy);
                            leaves.Add(currentCell.PackId64(), octreeLeaf);
                            node.SetChild(i, true);
                            node.SetData(i, octreeLeaf.GetFilteredValue());

                            changed = true;
                        }
                    }
                    nodes[nodeKey] = node;

                    if (canCollapse)
                        {
                        // Remove leaves
                        for (int i = 0; i < MyOctreeNode.CHILD_COUNT; i++)
                        {
                            if (node.HasChild(i))
                            {
                                ComputeChildCoord(i, out childOffset);
                                currentCell.CoordInLod = childBase + childOffset;

                                var childKey = currentCell.PackId64();
                                leaves.Remove(childKey);
                                node.SetChild(i, false);
                        }
                    }

                        // Remove node
                        nodes.Remove(nodeKey);

                        // Add leaf
                        var leafCellCopy = leafCell;
                        leafCellCopy.Lod += LeafLodCount;
                        var leafNew = new MyProviderLeaf(provider, dataType, ref leafCellCopy);
                        leaves.Add(leafKey, leafNew);
                }
            }
            }

            return changed;
        }
コード例 #40
0
        internal MyIsoMesh CreateMesh(IMyStorage storage, MyCellCoord coord)
        {
            // mk:NOTE This method must be thread safe. Called from worker threads.

            coord.CoordInLod += m_cellsOffset >> coord.Lod;

            if (m_voxelMap is MyVoxelPhysics)
            {
                var clipmapId = ((MyVoxelPhysics)m_voxelMap).Parent.Render.RenderObjectIDs[0];
                var clipmapCellId = MyCellCoord.GetClipmapCellHash(clipmapId, coord.PackId64());
                var isoMesh = MyPrecalcJobRender.IsoMeshCache.Read(clipmapCellId);
                if (isoMesh != null)
                {
                    return isoMesh;
                }
            }

            var min = coord.CoordInLod << MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS;
            var max = min + MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS;
            // overlap to neighbor; introduces extra data but it makes logic for raycasts and collisions simpler (no need to check neighbor cells)
            min -= 1;
            max += 2;
            return MyPrecalcComponent.IsoMesher.Precalc(storage, coord.Lod, min, max, false, false);
        }
コード例 #41
0
        private static unsafe void ReadRange(
            MyStorageDataCache target,
            ref Vector3I targetWriteOffset,
            MyStorageDataTypeEnum type,
            int treeHeight,
            Dictionary<UInt64, MyOctreeNode> nodes,
            Dictionary<UInt64, IMyOctreeLeafNode> leaves,
            int lodIndex,
            ref Vector3I minInLod,
            ref Vector3I maxInLod)
        {
            int stackIdx = 0;
            int stackSize = MySparseOctree.EstimateStackSize(treeHeight);
            MyCellCoord* stack = stackalloc MyCellCoord[stackSize];
            MyCellCoord data = new MyCellCoord(treeHeight + LeafLodCount, ref Vector3I.Zero);
            stack[stackIdx++] = data;
            MyCellCoord cell = new MyCellCoord();

            while (stackIdx > 0)
            {
                Debug.Assert(stackIdx <= stackSize);
                data = stack[--stackIdx];

                cell.Lod = data.Lod - LeafLodCount;
                cell.CoordInLod = data.CoordInLod;

                int lodDiff;
                IMyOctreeLeafNode leaf;
                if (leaves.TryGetValue(cell.PackId64(), out leaf))
                {
                    lodDiff = data.Lod - lodIndex;
                    var rangeMinInDataLod = minInLod >> lodDiff;
                    var rangeMaxInDataLod = maxInLod >> lodDiff;
                    if (data.CoordInLod.IsInsideInclusive(ref rangeMinInDataLod, ref rangeMaxInDataLod))
                    {
                        var nodePosInLod = data.CoordInLod << lodDiff;
                        var writeOffset = nodePosInLod - minInLod;
                        Vector3I.Max(ref writeOffset, ref Vector3I.Zero, out writeOffset);
                        writeOffset += targetWriteOffset;
                        var lodSizeMinusOne = new Vector3I((1 << lodDiff) - 1);
                        var minInLeaf = Vector3I.Clamp(minInLod - nodePosInLod, Vector3I.Zero, lodSizeMinusOne);
                        var maxInLeaf = Vector3I.Clamp(maxInLod - nodePosInLod, Vector3I.Zero, lodSizeMinusOne);
                        leaf.ReadRange(target, ref writeOffset, lodIndex, ref minInLeaf, ref maxInLeaf);
                    }
                    continue;
                }

                cell.Lod -= 1;
                lodDiff = data.Lod - 1 - lodIndex;
                var node = nodes[cell.PackId64()];

                var min = minInLod >> lodDiff;
                var max = maxInLod >> lodDiff;
                var nodePositionInChild = data.CoordInLod << 1;
                min -= nodePositionInChild;
                max -= nodePositionInChild;
                for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i)
                {
                    Vector3I childPosRelative;
                    ComputeChildCoord(i, out childPosRelative);
                    if (!childPosRelative.IsInsideInclusive(ref min, ref max))
                        continue;
                    if (lodIndex < data.Lod && node.HasChild(i))
                    {
                        Debug.Assert(stackIdx < stackSize);
                        stack[stackIdx++] = new MyCellCoord(data.Lod - 1, nodePositionInChild + childPosRelative);
                    }
                    else
                    {
                        var childMin = nodePositionInChild + childPosRelative;
                        childMin <<= lodDiff;
                        var writeOffset = childMin - minInLod;
                        Vector3I.Max(ref writeOffset, ref Vector3I.Zero, out writeOffset);
                        writeOffset += targetWriteOffset;
                        var nodeData = node.GetData(i);
                        if (lodDiff == 0)
                        {
                            target.Set(type, ref writeOffset, nodeData);
                        }
                        else
                        {
                            var childMax = childMin + ((1 << lodDiff) - 1);
                            Vector3I.Max(ref childMin, ref minInLod, out childMin);
                            Vector3I.Min(ref childMax, ref maxInLod, out childMax);
                            for (int z = childMin.Z; z <= childMax.Z; ++z)
                            for (int y = childMin.Y; y <= childMax.Y; ++y)
                            for (int x = childMin.X; x <= childMax.X; ++x)
                            {
                                Vector3I write = writeOffset;
                                write.X += x - childMin.X;
                                write.Y += y - childMin.Y;
                                write.Z += z - childMin.Z;
                                target.Set(type, ref write, nodeData);
                            }
                        }
                    }
                }
            }
        }