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) { bool enqueued = m_pendingChunksToWrite.Count > 0; 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); } } } } } if (!enqueued) { OperationsComponent.Add(this); } } else { using (m_storageLock.AcquireExclusiveUsing()) WriteRangeInternal(source, dataToWrite, ref voxelRangeMin, ref voxelRangeMax); } ProfilerShort.BeginNextBlock(GetType().Name + ".OnRangeChanged"); OnRangeChanged(voxelRangeMin, voxelRangeMax, dataToWrite); } finally { ProfilerShort.End(); } }
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_Vertices 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); }
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 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); }
public MyVoxelGeometry() { MyPrecalcComponent.AssertUpdateThread(); }
public MyWorkTracker(IEqualityComparer <TWorkId> comparer = null) { MyPrecalcComponent.AssertUpdateThread(); m_worksById = new Dictionary <TWorkId, TWork>(comparer ?? EqualityComparer <TWorkId> .Default); }
/// <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)RigidBody.GetShape(); 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(); }
protected virtual void OnComplete() { MyPrecalcComponent.AssertUpdateThread(); }
public void Complete(TWorkId id) { MyPrecalcComponent.AssertUpdateThread(); m_worksById.Remove(id); }
public bool TryGet(TWorkId id, out TWork work) { MyPrecalcComponent.AssertUpdateThread(); return(m_worksById.TryGetValue(id, out work)); }
public bool Exists(TWorkId id) { MyPrecalcComponent.AssertUpdateThread(); return(m_worksById.ContainsKey(id)); }
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(); }