Example #1
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);
            }
        }
        public override void LoadData()
        {
            m_instance = this;

            if (Environment.ProcessorCount <= 2)
            { // throttle down precalc on worker threads when it could hurt Update and Render thread.
                MyFakes.MAX_PRECALC_TIME_IN_MILLIS = 6f;
            }
            else
            {
                MyFakes.MAX_PRECALC_TIME_IN_MILLIS = 14f;
            }

        }
Example #3
0
        public void WriteRange(MyStorageData source, MyStorageDataTypeFlags dataToWrite, ref Vector3I voxelRangeMin, ref Vector3I voxelRangeMax)
        {
            MyPrecalcComponent.AssertUpdateThread();

            ProfilerShort.Begin(GetType().Name + ".WriteRange");
            try
            {
                m_compressedData = null;

                if (CachedWrites && (m_pendingChunksToWrite.Count < WriteCacheCap || OverlapsAnyCachedCell(voxelRangeMin, voxelRangeMax)))
                {
                    var lodDiff = VoxelChunk.SizeBits;

                    var chunkMin = voxelRangeMin >> lodDiff;
                    var chunkMax = voxelRangeMax >> lodDiff;

                    var pos = Vector3I.Zero;
                    for (pos.Z = chunkMin.Z; pos.Z <= chunkMax.Z; ++pos.Z)
                    {
                        for (pos.Y = chunkMin.Y; pos.Y <= chunkMax.Y; ++pos.Y)
                        {
                            for (pos.X = chunkMin.X; pos.X <= chunkMax.X; ++pos.X)
                            {
                                var celPos = pos << lodDiff;

                                var lodCkStart = pos << lodDiff;
                                lodCkStart = Vector3I.Max(lodCkStart, voxelRangeMin);

                                var lodCkEnd = ((pos + 1) << lodDiff) - 1;
                                lodCkEnd = Vector3I.Min(lodCkEnd, voxelRangeMax);

                                var targetOffset = lodCkStart - voxelRangeMin;

                                VoxelChunk chunk;
                                // Do not read the chunk if the range overlaps the whole chunk
                                var toRead = (lodCkEnd - lodCkStart + 1).Size != VoxelChunk.Volume ? dataToWrite : 0;
                                GetChunk(ref pos, out chunk, toRead);

                                lodCkStart -= celPos;
                                lodCkEnd   -= celPos;

                                using (chunk.Lock.AcquireExclusiveUsing())
                                {
                                    bool dirty = chunk.Dirty != 0;
                                    chunk.Write(source, dataToWrite, ref targetOffset, ref lodCkStart, ref lodCkEnd);
                                    if (!dirty)
                                    {
                                        m_pendingChunksToWrite.Enqueue(pos);
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    using (m_storageLock.AcquireExclusiveUsing())
                        WriteRangeInternal(source, dataToWrite, ref voxelRangeMin, ref voxelRangeMax);
                }

                ProfilerShort.BeginNextBlock(GetType().Name + ".OnRangeChanged");

                OnRangeChanged(voxelRangeMin, voxelRangeMax, dataToWrite);
            }
            finally
            {
                ProfilerShort.End();
            }
        }
Example #4
0
        public bool Intersects(ref BoundingSphereD localSphere)
        {
            MyPrecalcComponent.AssertUpdateThread();

            //  Get min and max cell coordinate where boundingBox can fit
            BoundingBoxD sphereBoundingBox = BoundingBoxD.CreateInvalid();

            sphereBoundingBox.Include(ref localSphere);
            Vector3I cellCoordMin, cellCoordMax;

            {
                Vector3D minD = sphereBoundingBox.Min;
                Vector3D maxD = sphereBoundingBox.Max;
                MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref minD, out cellCoordMin);
                MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref maxD, out cellCoordMax);
            }

            //  Fix min and max cell coordinates so they don't overlap the voxelmap
            ClampCellCoord(ref cellCoordMin);
            ClampCellCoord(ref cellCoordMax);

            MyCellCoord cell = new MyCellCoord();

            for (cell.CoordInLod.X = cellCoordMin.X; cell.CoordInLod.X <= cellCoordMax.X; cell.CoordInLod.X++)
            {
                for (cell.CoordInLod.Y = cellCoordMin.Y; cell.CoordInLod.Y <= cellCoordMax.Y; cell.CoordInLod.Y++)
                {
                    for (cell.CoordInLod.Z = cellCoordMin.Z; cell.CoordInLod.Z <= cellCoordMax.Z; cell.CoordInLod.Z++)
                    {
                        //  If no overlap between bounding box of data cell and the sphere
                        BoundingBox cellBoundingBox;
                        MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref cell.CoordInLod, out cellBoundingBox);
                        if (cellBoundingBox.Intersects(ref localSphere) == false)
                        {
                            continue;
                        }

                        //  Get cell from cache. If not there, precalc it and store in the cache.
                        //  If null is returned, we know that cell doesn't contain any triangleVertexes so we don't need to do intersections.
                        CellData cachedData = GetCell(ref cell);

                        if (cachedData == null)
                        {
                            continue;
                        }

                        for (int i = 0; i < cachedData.VoxelTrianglesCount; i++)
                        {
                            MyVoxelTriangle voxelTriangle = cachedData.VoxelTriangles[i];

                            MyTriangle_Vertexes triangle;
                            cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex0, out triangle.Vertex0);
                            cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex1, out triangle.Vertex1);
                            cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex2, out triangle.Vertex2);

                            BoundingBox localTriangleAABB = BoundingBox.CreateInvalid();
                            localTriangleAABB.Include(ref triangle.Vertex0);
                            localTriangleAABB.Include(ref triangle.Vertex1);
                            localTriangleAABB.Include(ref triangle.Vertex2);

                            //  First test intersection of triangle's bounding box with line's bounding box. And only if they overlap or intersect, do further intersection tests.
                            if (localTriangleAABB.Intersects(ref localSphere))
                            {
                                PlaneD trianglePlane = new PlaneD(triangle.Vertex0, triangle.Vertex1, triangle.Vertex2);

                                if (MyUtils.GetSphereTriangleIntersection(ref localSphere, ref trianglePlane, ref triangle) != null)
                                {
                                    //  If intersection found - we are finished. We don't need to look for more.
                                    return(true);
                                }
                            }
                        }
                    }
                }
            }

            return(false);
        }
Example #5
0
 public MyVoxelGeometry()
 {
     MyPrecalcComponent.AssertUpdateThread();
 }
Example #6
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, false);
                }
                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);
        }
Example #7
0
        /// <param name="minVoxelChanged">Inclusive min.</param>
        /// <param name="maxVoxelChanged">Inclusive max.</param>
        internal void InvalidateRange(Vector3I minVoxelChanged, Vector3I maxVoxelChanged)
        {
            MyPrecalcComponent.AssertUpdateThread();
            ProfilerShort.Begin("MyVoxelPhysicsBody.InvalidateRange");

            minVoxelChanged -= MyPrecalcComponent.InvalidatedRangeInflate;
            maxVoxelChanged += MyPrecalcComponent.InvalidatedRangeInflate;
            m_voxelMap.Storage.ClampVoxelCoord(ref minVoxelChanged);
            m_voxelMap.Storage.ClampVoxelCoord(ref maxVoxelChanged);

            Vector3I minCellChanged, maxCellChanged;

            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref minVoxelChanged, out minCellChanged);
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxVoxelChanged, out maxCellChanged);

            Vector3I minCellChangedVoxelMap, maxCellChangedVoxelMap;

            minCellChangedVoxelMap = minCellChanged - m_cellsOffset;
            maxCellChangedVoxelMap = maxCellChanged - m_cellsOffset;
            var maxCell = m_voxelMap.Size - 1;

            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxCell, out maxCell);
            Vector3I.Min(ref maxCellChangedVoxelMap, ref maxCell, out maxCellChangedVoxelMap);

            Debug.Assert(RigidBody != null, "RigidBody in voxel physics is null! This must not happen.");
            if (RigidBody != null)
            {
                var shape = (HkUniformGridShape)GetShape();//RigidBody.GetShape();
                Debug.Assert(shape.Base.IsValid);
                var tmpBuffer    = m_cellsToGenerateBuffer;
                int invalidCount = shape.InvalidateRange(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap, tmpBuffer);
                if (invalidCount > tmpBuffer.Length)
                {
                    // Not storing this new buffer in static variable since this is just temporary and potentially large.
                    // Static variable could be potentially the same as leak.
                    tmpBuffer = new Vector3I[invalidCount];
                    int invalidCount2 = shape.InvalidateRange(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap, tmpBuffer);
                    Debug.Assert(invalidCount == invalidCount2);
                    invalidCount = invalidCount2;
                }

                Debug.Assert(invalidCount <= tmpBuffer.Length);
                for (int i = 0; i < invalidCount; i++)
                {
                    InvalidCells.Add(tmpBuffer[i]);
                }
                if (RunningBatchTask == null && InvalidCells.Count != 0)
                {
                    MyPrecalcComponent.PhysicsWithInvalidCells.Add(this);
                }
            }

            if (minCellChangedVoxelMap == Vector3I.Zero && maxCellChangedVoxelMap == maxCell)
            {
                m_workTracker.CancelAll();
            }
            else
            {
                var cell = minCellChanged;
                for (var it = new Vector3I.RangeIterator(ref minCellChanged, ref maxCellChanged);
                     it.IsValid(); it.GetNext(out cell))
                {
                    m_workTracker.Cancel(cell);
                }
            }

            m_needsShapeUpdate = true;

            ProfilerShort.End();

            m_voxelMap.RaisePhysicsChanged();
        }
 protected override void UnloadData()
 {
     m_highPriorityJobs.Clear();
     m_lowPriorityJobs.Clear();
     m_instance = null;
 }
Example #9
0
 protected virtual void OnComplete()
 {
     MyPrecalcComponent.AssertUpdateThread();
 }
Example #10
0
        public void Complete(TWorkId id)
        {
            MyPrecalcComponent.AssertUpdateThread();

            m_worksById.Remove(id);
        }
Example #11
0
        public bool TryGet(TWorkId id, out TWork work)
        {
            MyPrecalcComponent.AssertUpdateThread();

            return(m_worksById.TryGetValue(id, out work));
        }
Example #12
0
        public bool Exists(TWorkId id)
        {
            MyPrecalcComponent.AssertUpdateThread();

            return(m_worksById.ContainsKey(id));
        }
Example #13
0
        internal void InvalidateRange(Vector3I minVoxelChanged, Vector3I maxVoxelChanged, int lod)
        {
            MyPrecalcComponent.AssertUpdateThread();

            // No physics there ever was so we don't care.
            if (!m_bodiesInitialized)
            {
                return;
            }

            if (m_queueInvalidation)
            {
                if (m_queuedRange.Max.X < 0)
                {
                    m_queuedRange = new BoundingBoxI(minVoxelChanged, maxVoxelChanged);
                }
                else
                {
                    var bb = new BoundingBoxI(minVoxelChanged, maxVoxelChanged);
                    m_queuedRange.Include(ref bb);
                }
                return;
            }

            ProfilerShort.Begin("MyVoxelPhysicsBody.InvalidateRange");
            minVoxelChanged -= 1; // MyPrecalcComponent.InvalidatedRangeInflate;
            maxVoxelChanged += 1; //MyPrecalcComponent.InvalidatedRangeInflate;
            m_voxelMap.Storage.ClampVoxelCoord(ref minVoxelChanged);
            m_voxelMap.Storage.ClampVoxelCoord(ref maxVoxelChanged);

            Vector3I minCellChanged, maxCellChanged;

            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref minVoxelChanged, out minCellChanged);
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxVoxelChanged, out maxCellChanged);

            Vector3I minCellChangedVoxelMap, maxCellChangedVoxelMap;

            minCellChangedVoxelMap = (minCellChanged - m_cellsOffset) >> lod;
            maxCellChangedVoxelMap = (maxCellChanged - m_cellsOffset) >> lod;

            var maxCell = m_voxelMap.Size - 1;

            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxCell, out maxCell);
            maxCell >>= lod;
            Vector3I.Min(ref maxCellChangedVoxelMap, ref maxCell, out maxCellChangedVoxelMap);

            Debug.Assert(RigidBody != null, "RigidBody in voxel physics is null! This must not happen.");

            var rb = GetRigidBody(lod);

            Debug.Assert(rb != null, "RigidBody in voxel physics is null! This must not happen.");

            if (rb != null)
            {
                HkUniformGridShape shape = (HkUniformGridShape)rb.GetShape();
                Debug.Assert(shape.Base.IsValid);


                var numCells = (maxCellChangedVoxelMap - minCellChangedVoxelMap + 1).Size;
                if (numCells >= m_cellsToGenerateBuffer.Length)
                {
                    m_cellsToGenerateBuffer = new Vector3I[MathHelper.GetNearestBiggerPowerOfTwo(numCells)];
                }

                var tmpBuffer    = m_cellsToGenerateBuffer;
                int invalidCount = shape.InvalidateRange(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap, tmpBuffer);
                Debug.Assert(invalidCount <= tmpBuffer.Length);

                //if (numCells <= 8)
                //shape.InvalidateRangeImmediate(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap);

                Debug.Assert(invalidCount <= tmpBuffer.Length);
                for (int i = 0; i < invalidCount; i++)
                {
                    InvalidCells[lod].Add(tmpBuffer[i]);
                }

                if (RunningBatchTask[lod] == null && InvalidCells[lod].Count != 0)
                {
                    MyPrecalcComponent.PhysicsWithInvalidCells.Add(this);
                }
            }

            if (minCellChangedVoxelMap == Vector3I.Zero && maxCellChangedVoxelMap == maxCell)
            {
                m_workTracker.CancelAll();
            }
            else
            {
                var cell = minCellChanged;
                for (var it = new Vector3I_RangeIterator(ref minCellChanged, ref maxCellChanged);
                     it.IsValid(); it.GetNext(out cell))
                {
                    m_workTracker.Cancel(new MyCellCoord(lod, cell));
                }
            }

            m_needsShapeUpdate = true;

            ProfilerShort.End();

            m_voxelMap.RaisePhysicsChanged();
        }
        internal void InvalidateRange(Vector3I minVoxelChanged, Vector3I maxVoxelChanged, int lod)
        {
            MyPrecalcComponent.AssertUpdateThread();
            // No physics there ever was so we don't care.
            if (!m_bodiesInitialized)
            {
                return;
            }

            if (m_queueInvalidation)
            {
                if (m_queuedRange.Max.X < 0)
                {
                    m_queuedRange = new BoundingBoxI(minVoxelChanged, maxVoxelChanged);
                }
                else
                {
                    var bb = new BoundingBoxI(minVoxelChanged, maxVoxelChanged);
                    m_queuedRange.Include(ref bb);
                }
                return;
            }

            ProfilerShort.Begin("MyVoxelPhysicsBody.InvalidateRange");
            minVoxelChanged -= MyPrecalcComponent.InvalidatedRangeInflate;
            maxVoxelChanged += MyPrecalcComponent.InvalidatedRangeInflate;
            m_voxelMap.Storage.ClampVoxelCoord(ref minVoxelChanged);
            m_voxelMap.Storage.ClampVoxelCoord(ref maxVoxelChanged);

            Vector3I minCellChanged, maxCellChanged;

            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref minVoxelChanged, out minCellChanged);
            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxVoxelChanged, out maxCellChanged);

            Vector3I minCellChangedVoxelMap, maxCellChangedVoxelMap;

            minCellChangedVoxelMap = (minCellChanged - m_cellsOffset) >> lod;
            maxCellChangedVoxelMap = (maxCellChanged - m_cellsOffset) >> lod;

            var maxCell = m_voxelMap.Size - 1;

            MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxCell, out maxCell);
            maxCell >>= lod;
            Vector3I.Min(ref maxCellChangedVoxelMap, ref maxCell, out maxCellChangedVoxelMap);

            Debug.Assert(RigidBody != null, "RigidBody in voxel physics is null! This must not happen.");

            var rb = GetRigidBody(lod);

            Debug.Assert(rb != null, "RigidBody in voxel physics is null! This must not happen.");

            if (rb != null)
            {
                HkUniformGridShape shape = (HkUniformGridShape)rb.GetShape();
                Debug.Assert(shape.Base.IsValid);

                var tmpBuffer    = m_cellsToGenerateBuffer;
                int invalidCount = shape.InvalidateRange(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap, tmpBuffer);
                if (invalidCount > tmpBuffer.Length)
                {
                    // Not storing this new buffer in static variable since this is just temporary and potentially large.
                    // Static variable could be potentially the same as leak.
                    tmpBuffer = new Vector3I[invalidCount];
                    int invalidCount2 = shape.InvalidateRange(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap, tmpBuffer);
                    Debug.Assert(invalidCount == invalidCount2);
                    invalidCount = invalidCount2;
                }

                shape.InvalidateRangeImmediate(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap);
                Debug.Assert(invalidCount <= tmpBuffer.Length);
                for (int i = 0; i < invalidCount; i++)
                {
                    InvalidCells.Add(tmpBuffer[i]);
                }
                if (RunningBatchTask == null && InvalidCells.Count != 0)
                {
                    MyPrecalcComponent.PhysicsWithInvalidCells.Add(this);
                }
            }

            if (minCellChangedVoxelMap == Vector3I.Zero && maxCellChangedVoxelMap == maxCell)
            {
                m_workTracker.CancelAll();
            }
            else
            {
                var cell = minCellChanged;
                for (var it = new Vector3I.RangeIterator(ref minCellChanged, ref maxCellChanged);
                     it.IsValid(); it.GetNext(out cell))
                {
                    m_workTracker.Cancel(new MyCellCoord(lod, cell));
                }
            }

            m_needsShapeUpdate = true;

            ProfilerShort.End();

            m_voxelMap.RaisePhysicsChanged();
        }
 protected override void UnloadData()
 {
     m_highPriorityJobs.Clear();
     m_lowPriorityJobs.Clear();
     m_instance = null;
 }
 protected override void UnloadData()
 {
     m_instance = null;
 }
Example #17
0
        public MyWorkTracker(IEqualityComparer <TWorkId> comparer = null)
        {
            MyPrecalcComponent.AssertUpdateThread();

            m_worksById = new Dictionary <TWorkId, TWork>(comparer ?? EqualityComparer <TWorkId> .Default);
        }