private void OnDepositQueryComplete(MyDepositQuery query, ConcurrentCachingList <MyEntityOreDeposit> deposits, List <Vector3I> emptyCells) { foreach (var deposit in deposits) { Vector3I depositCell = deposit.CellCoord; m_depositsByCellCoord[depositCell] = deposit; //RegisterMarker(deposit); //MyHud.OreMarkers.RegisterMarker(deposit); } foreach (var emptyCell in emptyCells) { m_emptyCellCoord.Add(emptyCell); } m_tasksRunning--; var bb = new BoundingBoxI(query.Min, query.Max); m_completed += bb.Size.Size; Logger.Instance.LogDebugOnGameThread($"Completed: {m_completed}"); if (m_tasksRunning == 0) { Scanning = false; } }
public ContainmentType Intersect(ref BoundingBoxI box, int lod, bool exhaustiveContainmentCheck = true) { BoundingBoxI xi = box; xi.Translate(-this.m_voxelRangeMin); return(this.m_octree.Intersect(ref xi, lod, exhaustiveContainmentCheck)); }
public void LoadDetailsSync() { ReadVoxelDetails(SourceVoxelFilepath ?? VoxelFilepath); if (_voxelMap != null && (MaterialAssets == null || MaterialAssets.Count == 0)) { Dictionary <string, long> details = _voxelMap.RefreshAssets(); _contentBounds = _voxelMap.BoundingContent; _inflatedContentBounds = _voxelMap.InflatedBoundingContent; _voxCells = _voxelMap.VoxCells; Center = new Vector3D(_voxelMap.ContentCenter.X + 0.5f + PositionX, _voxelMap.ContentCenter.Y + 0.5f + PositionY, _voxelMap.ContentCenter.Z + 0.5f + PositionZ); var sum = details.Values.ToList().Sum(); var list = new List <VoxelMaterialAssetModel>(); foreach (var kvp in details) { list.Add(new VoxelMaterialAssetModel { MaterialName = kvp.Key, Volume = (double)kvp.Value / 255, Percent = (double)kvp.Value / (double)sum }); } MaterialAssets = list; } }
public static BoundingBoxI TransformBoundingBox(BoundingBoxI box, ref MatrixI matrix) { Vector3I a, b; Vector3I.Transform(ref box.Min, ref matrix, out a); Vector3I.Transform(ref box.Max, ref matrix, out b); return(new BoundingBoxI(Vector3I.Min(a, b), Vector3I.Max(a, b))); }
public ContainmentType Intersect(ref BoundingBoxI box, bool lazy) { BoundingBoxI localCoords = box; localCoords.Translate(-m_voxelRangeMin); return(m_octree.Intersect(ref localCoords, lazy)); }
private static bool IntersectsVoxelSurface(OrientedBoundingBoxD box) { var data = VoxelData; using (PoolManager.Get(out List <MyEntity> entities)) { MyGamePruningStructure.GetTopmostEntitiesInBox(box.GetAABB(), entities, MyEntityQueryType.Static); foreach (var ent in entities) { if (ent is MyVoxelBase voxel && !(ent is MyVoxelPhysics)) { var invWorld = voxel.PositionComp.WorldMatrixInvScaled; var storageBounds = BoundingBoxD.CreateInvalid(); var voxelOffset = (voxel.Size >> 1) + voxel.StorageMin; var storageObb = box; storageObb.Transform(invWorld); storageObb.HalfExtent /= voxel.VoxelSize; storageObb.Center = storageObb.Center / voxel.VoxelSize + voxelOffset; storageBounds.Include(storageObb.GetAABB()); var storageMin = Vector3I.Max(Vector3I.Floor(storageBounds.Min), voxel.StorageMin); var storageMax = Vector3I.Min(Vector3I.Ceiling(storageBounds.Max), voxel.StorageMax); var localBox = new BoundingBoxI(storageMin, storageMax); localBox.Inflate(1); var floatBox = new BoundingBox(localBox); if (voxel.IntersectStorage(ref floatBox) == ContainmentType.Disjoint) { continue; } data.Resize(storageMin, storageMax); voxel.Storage.ReadRange(data, MyStorageDataTypeFlags.Content, 0, storageMin, storageMax); foreach (var pt in new BoundingBoxI(Vector3I.Zero, storageMax - storageMin).EnumeratePoints()) { var voxelBox = new BoundingBoxD(storageMin + pt, storageMin + pt + 1); var containment = storageObb.Contains(ref voxelBox); if (containment == ContainmentType.Disjoint) { continue; } var tmpPt = pt; var index = data.ComputeLinear(ref tmpPt); var content = data.Content(index); if (containment == ContainmentType.Intersects && content >= 127) { return(true); } if (containment == ContainmentType.Contains && content > 0) { return(true); } } } } } return(false); }
public ContainmentType Intersect(BoundingBoxI box, int lod) { if (this.Closed) { return(ContainmentType.Disjoint); } BoundingBox box2 = new BoundingBox(box); box2.Translate(-this.Shape.Center()); return(this.Shape.IntersectBoundingBox(ref box2, 1f)); }
private bool QueryEmptyOrFull(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { BoundingBoxI box = new BoundingBoxI(new Vector3I(minX, minY, minZ), new Vector3I(maxX, maxY, maxZ)); if (box.Volume() < 100f) { return(false); } bool flag = this.m_voxelMap.Storage.Intersect(ref box, 0, true) != ContainmentType.Intersects; BoundingBoxD xd = new BoundingBoxD(new Vector3((float)minX, (float)minY, (float)minZ) * 8f, new Vector3((float)maxX, (float)maxY, (float)maxZ) * 8f); xd.TransformFast(base.Entity.WorldMatrix); MyOrientedBoundingBoxD xd1 = new MyOrientedBoundingBoxD(xd, base.Entity.WorldMatrix); MyRenderProxy.DebugDrawAABB(xd, flag ? Color.Green : Color.Red, 1f, 1f, false, false, false); return(flag); }
public static void RayCastGrid(this IMyCubeGrid grid, Vector3 rayStart, Vector3 direction, Action <Vector3I> visitor) { Matrix worldToLocal = Matrix.Invert(grid.WorldMatrix); direction.Normalize(); Vector3 transformedDirection = Vector3.TransformNormal(direction, worldToLocal); Vector3 currentPointF = Vector3.Transform(rayStart, worldToLocal) / grid.GridSize; Vector3I currentPoint = Vector3I.Round(currentPointF); if (!Inside(grid.Min, grid.Max, currentPoint)) { //find intersection BoundingBoxI bbI = new BoundingBoxI(grid.Min, grid.Max); var hit = bbI.Intersects(new Ray(currentPointF, transformedDirection)); if (!hit.HasValue) { //Program.instance.Log($"No misses bounding box"); return; //no intersection } currentPointF += (float)hit.Value * transformedDirection; currentPoint = Vector3I.Round(currentPointF); } //Program.instance.Log($"Starting at: {currentPoint}"); //Program.instance.Log($"Direction at: {transformedDirection}"); while (Inside(grid.Min, grid.Max, currentPoint)) { if (grid.CubeExists(currentPoint)) { visitor(currentPoint); } float toXShift = ClosestGridBlockChange(currentPointF.X, transformedDirection.X); float toYShift = ClosestGridBlockChange(currentPointF.Y, transformedDirection.Y); float toZShift = ClosestGridBlockChange(currentPointF.Z, transformedDirection.Z); currentPointF += transformedDirection * Min(toXShift, toYShift, toZShift); currentPoint = Vector3I.Round(currentPointF); //Program.instance.Log($"Shift by: {toXShift}, {toYShift}, {toZShift}"); //Program.instance.Log($"Walk:{currentPoint}"); } }
public ContainmentType Intersect(BoundingBoxI box, bool lazy) { ContainmentType ct = ContainmentType.Disjoint; BoundingBox bb = new BoundingBox(box); BoundingSphere sp = new BoundingSphere(bb.Center, bb.Extents.Length() / 2f); // Check filled shapes. foreach (var shape in m_data.FilledShapes) { var c = shape.Contains(ref bb, ref sp, 1f); if (c == ContainmentType.Contains) { ct = c; } else if (c == ContainmentType.Intersects && ct == ContainmentType.Disjoint) { ct = c; } } // Check shapes removed, we don't check how they are removed so we only discard if the removed shape covers the whole bb. if (ct != ContainmentType.Disjoint) { foreach (var shape in m_data.RemovedShapes) { var c = shape.Contains(ref bb, ref sp, 1f); if (c == ContainmentType.Contains) { ct = ContainmentType.Disjoint; break; } else if (c == ContainmentType.Intersects) { ct = ContainmentType.Intersects; } } } return(ct); }
internal MyVoxelPhysicsBody(MyVoxelBase voxelMap, float phantomExtend, float predictionSize = 3f, bool lazyPhysics = false) : base(voxelMap, RigidBodyFlag.RBF_STATIC) { this.RunningBatchTask = new MyPrecalcJobPhysicsBatch[2]; this.m_nearbyEntities = new HashSet <IMyEntity>(); this.m_nearbyEntitiesLock = new FastResourceLock(); this.m_workTracker = new MyWorkTracker <MyCellCoord, MyPrecalcJobPhysicsPrefetch>(MyCellCoord.Comparer); this.m_cellsOffset = new Vector3I(0, 0, 0); this.m_staticForCluster = true; this.m_predictionSize = 3f; this.m_queuedRange = new BoundingBoxI(-1, -1); this.InvalidCells = new HashSet <Vector3I>[] { new HashSet <Vector3I>(), new HashSet <Vector3I>() }; this.m_predictionSize = predictionSize; this.m_phantomExtend = phantomExtend; this.m_voxelMap = voxelMap; Vector3I vectori1 = this.m_voxelMap.Size >> 3; this.m_cellsOffset = this.m_voxelMap.StorageMin >> 3; if (!MyFakes.ENABLE_LAZY_VOXEL_PHYSICS || !lazyPhysics) { this.CreateRigidBodies(); } base.MaterialType = VRage.Game.MyMaterialType.ROCK; }
private void ComputeSectorParameters() { // face size is the length of an edge of a cube with half diagonal r. // this is equal to sqrt(2) * r m_sectorFaceSize = MaximumRadius * 1.41421356237309504880; // Ensure at least one sector. if (m_sectorFaceSize < MIN_SECTOR_SIZE) { m_numSectors = 1; m_sectorSize = m_sectorFaceSize; } else { m_numSectors = (int)Math.Floor(m_sectorFaceSize / MIN_SECTOR_SIZE); m_sectorSize = m_sectorFaceSize / m_numSectors; } m_sectorBox = new BoundingBoxI(0, m_numSectors - 1); m_sectorDensity = Generator.SectorDensity; m_itemsPerSector = m_sectorDensity * m_sectorSize * m_sectorSize; }
private void FillOutOfBounds(MyStorageData target, MyStorageDataTypeEnum type, ref Vector3I woffset, int lodIndex, Vector3I minInLod, Vector3I maxInLod) { var value = MyVoxelConstants.DefaultValue(type); var size = new Vector3I((1 << (m_treeHeight + LeafLodCount - lodIndex)) - 1); var offset = woffset - minInLod; var req = new BoundingBoxI(minInLod, maxInLod); var tree = new BoundingBoxI(Vector3I.Zero, size); if (req.Intersects(ref tree) != true) { target.BlockFill(type, offset + minInLod, offset + maxInLod, value); return; } // Left if (minInLod.X < 0) { var min = minInLod; var max = maxInLod; max.X = -1; minInLod.X = 0; target.BlockFill(type, min + offset, max + offset, value); } // Right if (maxInLod.X > size.X) { var min = minInLod; var max = maxInLod; min.X = size.X+1; minInLod.X = size.X; target.BlockFill(type, min + offset, max + offset, value); } // Top if (minInLod.Y < 0) { var min = minInLod; var max = maxInLod; max.Y = -1; minInLod.Y = 0; target.BlockFill(type, min + offset, max + offset, value); } // Bottom if (maxInLod.Y > size.Y) { var min = minInLod; var max = maxInLod; min.Y = size.Y + 1; minInLod.Y = size.Y; target.BlockFill(type, min + offset, max + offset, value); } // Back if (minInLod.Y < 0) { var min = minInLod; var max = maxInLod; max.Y = -1; minInLod.Y = 0; target.BlockFill(type, min + offset, max + offset, value); } // Front if (maxInLod.Y > size.Y) { var min = minInLod; var max = maxInLod; min.Y = size.Y + 1; minInLod.Y = size.Y; target.BlockFill(type, min + offset, max + offset, value); } }
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); } } }
// To help debug even when using stackalloc public unsafe bool IntersectInternalWStack(ref LineD line, MyCellCoord * stack, int stackSize) { #else int stackSize = MySparseOctree.EstimateStackSize(m_treeHeight); MyCellCoord* stack = stackalloc MyCellCoord[stackSize]; #endif var finalB = BoundingBoxD.CreateInvalid(); LineD result; result.From = line.To; result.To = line.From; MyCellCoord data = new MyCellCoord(m_treeHeight + LeafLodCount, ref Vector3I.Zero); int stackIdx = 0; stack[stackIdx++] = data; MyCellCoord cell = new MyCellCoord(); BoundingBoxI bb = new BoundingBoxI(new Vector3I(Vector3.Min(line.From, line.To)), new Vector3I(Vector3.Ceiling(Vector3.Max(line.From, line.To)))); double startOfft, endOfft; while (stackIdx > 0) { Debug.Assert(stackIdx <= stackSize); data = stack[--stackIdx]; cell.Lod = Math.Max(data.Lod - LeafLodCount, 0); cell.CoordInLod = data.CoordInLod; int lodDiff; IMyOctreeLeafNode leaf; if (m_contentLeaves.TryGetValue(cell.PackId64(), out leaf)) { lodDiff = data.Lod; var rangeMinInDataLod = bb.Min >> lodDiff; var rangeMaxInDataLod = bb.Max >> lodDiff; if (data.CoordInLod.IsInsideInclusive(ref rangeMinInDataLod, ref rangeMaxInDataLod)) { var start = rangeMinInDataLod << data.Lod; var end = (rangeMaxInDataLod) << data.Lod; var leafBounds = new BoundingBoxD(start, end); LineD ll; leafBounds.Intersect(ref line, out ll); if (leaf.Intersect(ref ll, out startOfft, out endOfft)) { if (finalB.Contains(ll.From) == ContainmentType.Disjoint) { result.From = ll.From; finalB.Include(ll.From); } if (finalB.Contains(ll.To) == ContainmentType.Disjoint) { result.To = ll.To; finalB.Include(ll.To); } } } continue; } cell.Lod -= 1; lodDiff = data.Lod - 1; var node = m_contentNodes[cell.PackId64()]; var min = bb.Min >> lodDiff; var max = bb.Max >> 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; BoundingBoxD nodeBounds; nodeBounds.Min = childPosRelative + cell.CoordInLod << lodDiff; nodeBounds.Max = nodeBounds.Min + (1 << data.Lod); if (finalB.Contains(nodeBounds) == ContainmentType.Contains) continue; if (!nodeBounds.Intersects(ref line)) continue; if (node.HasChild(i)) { Debug.Assert(stackIdx < stackSize); stack[stackIdx++] = new MyCellCoord(data.Lod - 1, nodePositionInChild + childPosRelative); } } } if (!finalB.Valid) return false; line.To = result.To; line.From = result.From; line.Length = (result.To - result.From).Length(); return true; }
private void MergeAsteroidVolumeInto(ref MyVoxelMap newAsteroid, Vector3D min, StructureVoxelModel modelPrimary, StructureVoxelModel modelSecondary, Vector3D minPrimary, Vector3D minSecondary) { var filenameSecondary = modelSecondary.SourceVoxelFilepath ?? modelSecondary.VoxelFilepath; var filenamePrimary = modelPrimary.SourceVoxelFilepath ?? modelPrimary.VoxelFilepath; Vector3I block; Vector3I newBlock; Vector3I cacheSize; var asteroid = new MyVoxelMap(); asteroid.Load(filenameSecondary); BoundingBoxI content = modelSecondary.InflatedContentBounds; for (block.Z = content.Min.Z; block.Z <= content.Max.Z; block.Z += 64) { for (block.Y = content.Min.Y; block.Y <= content.Max.Y; block.Y += 64) { for (block.X = content.Min.X; block.X <= content.Max.X; block.X += 64) { var cache = new MyStorageData(); cacheSize = new Vector3I(MathHelper.Min(content.Max.X, block.X + 63) - block.X + 1, MathHelper.Min(content.Max.Y, block.Y + 63) - block.Y + 1, MathHelper.Min(content.Max.Z, block.Z + 63) - block.Z + 1); cache.Resize(cacheSize); asteroid.Storage.ReadRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, block, block + cacheSize - 1); newBlock = ((minSecondary - min) + (Vector3D)(block - content.Min)).RoundToVector3I(); newAsteroid.Storage.WriteRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, newBlock, newBlock + cacheSize - 1); } } } asteroid.Load(filenamePrimary); content = modelPrimary.InflatedContentBounds; for (block.Z = content.Min.Z; block.Z <= content.Max.Z; block.Z += 64) { for (block.Y = content.Min.Y; block.Y <= content.Max.Y; block.Y += 64) { for (block.X = content.Min.X; block.X <= content.Max.X; block.X += 64) { var cache = new MyStorageData(); cacheSize = new Vector3I(MathHelper.Min(content.Max.X, block.X + 63) - block.X + 1, MathHelper.Min(content.Max.Y, block.Y + 63) - block.Y + 1, MathHelper.Min(content.Max.Z, block.Z + 63) - block.Z + 1); cache.Resize(cacheSize); asteroid.Storage.ReadRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, block, block + cacheSize - 1); newBlock = ((minPrimary - min) + (Vector3D)(block - content.Min)).RoundToVector3I(); var newCache = new MyStorageData(); newCache.Resize(cacheSize); newAsteroid.Storage.ReadRange(newCache, MyStorageDataTypeFlags.ContentAndMaterial, 0, newBlock, newBlock + cacheSize - 1); Vector3I p; for (p.Z = 0; p.Z < cacheSize.Z; ++p.Z) { for (p.Y = 0; p.Y < cacheSize.Y; ++p.Y) { for (p.X = 0; p.X < cacheSize.X; ++p.X) { byte volume = cache.Content(ref p); byte material = cache.Material(ref p); if (volume > 0) { byte existingVolume = newCache.Content(ref p); if (volume > existingVolume) { newCache.Content(ref p, volume); } // Overwrites secondary material with primary. newCache.Material(ref p, material); } else { // try to find cover material. Vector3I[] points = CreateTestPoints(p, cacheSize - 1); for (int i = 0; i < points.Length; i++) { byte testVolume = cache.Content(ref points[i]); if (testVolume > 0) { material = cache.Material(ref points[i]); newCache.Material(ref p, material); break; } } } } } } newAsteroid.Storage.WriteRange(newCache, MyStorageDataTypeFlags.ContentAndMaterial, newBlock, newBlock + cacheSize - 1); } } } }
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(); }
public ContainmentType Intersect(BoundingBoxI box, bool lazy) { if (Closed) { Debug.Fail("Storage closed!"); return ContainmentType.Disjoint; } BoundingBox bbox = new BoundingBox(box); bbox.Translate(-Shape.Center()); // Bring to center local return Shape.IntersectBoundingBox(ref bbox, 1.0f); }
internal unsafe ContainmentType Intersect(ref BoundingBoxI box, bool lazy) { int stackIdx = 0; int stackSize = MySparseOctree.EstimateStackSize(m_treeHeight); MyCellCoord *stack = stackalloc MyCellCoord[stackSize]; MyCellCoord data = new MyCellCoord(m_treeHeight - 1, ref Vector3I.Zero); stack[stackIdx++] = data; Vector3I minInLod = box.Min; Vector3I maxInLod = box.Max; MyOctreeNode node; Vector3I childPosRelative, min, max, nodePositionInChild; int lodDiff; // TODO(DI): Add support for checking for containment somehow, this needs neighbourhood information which kinda sucks. ContainmentType cont = ContainmentType.Disjoint; while (stackIdx > 0) { Debug.Assert(stackIdx <= stackSize); data = stack[--stackIdx]; node = m_nodes[data.PackId32()]; lodDiff = data.Lod; min = minInLod >> lodDiff; max = maxInLod >> lodDiff; nodePositionInChild = data.CoordInLod << 1; min -= nodePositionInChild; max -= nodePositionInChild; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childPosRelative); if (!childPosRelative.IsInsideInclusive(ref min, ref max)) { continue; } if (data.Lod > 0 && node.HasChild(i)) { Debug.Assert(stackIdx < stackSize); stack[stackIdx++] = new MyCellCoord(data.Lod - 1, nodePositionInChild + childPosRelative); } else { var nodeData = node.Data[i]; if (lodDiff == 0) { if (nodeData != 0) { return(ContainmentType.Intersects); } } else { BoundingBoxI nodeBox; nodeBox.Min = nodePositionInChild + childPosRelative; nodeBox.Min <<= lodDiff; nodeBox.Max = nodeBox.Min + (1 << lodDiff) - 1; Vector3I.Max(ref nodeBox.Min, ref minInLod, out nodeBox.Min); Vector3I.Min(ref nodeBox.Max, ref maxInLod, out nodeBox.Max); bool res; nodeBox.Intersects(ref nodeBox, out res); if (res) { return(ContainmentType.Intersects); } } } } } return(cont); }
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(); }
internal unsafe ContainmentType Intersect(ref BoundingBoxI box, int lod, bool exhaustiveContainmentCheck = true) { MyCellCoord *coordPtr = (MyCellCoord *)stackalloc byte[(((IntPtr)EstimateStackSize(this.m_treeHeight)) * sizeof(MyCellCoord))]; MyCellCoord coord = new MyCellCoord(this.m_treeHeight - 1, ref Vector3I.Zero); int index = 0 + 1; coordPtr[index] = coord; Vector3I min = box.Min; Vector3I max = box.Max; ContainmentType disjoint = ContainmentType.Disjoint; while (index > 0) { coord = coordPtr[--index]; MyOctreeNode node = this.m_nodes[coord.PackId32()]; int num3 = coord.Lod; Vector3I vectori6 = coord.CoordInLod << 1; Vector3I vectori4 = (min >> num3) - vectori6; Vector3I vectori5 = (max >> num3) - vectori6; for (int i = 0; i < 8; i++) { Vector3I vectori3; this.ComputeChildCoord(i, out vectori3); if (vectori3.IsInsideInclusiveEnd(ref vectori4, ref vectori5)) { if ((coord.Lod > 0) && node.HasChild(i)) { index++; coordPtr[index] = new MyCellCoord(coord.Lod - 1, (Vector3I)(vectori6 + vectori3)); } else { byte num5 = &node.Data.FixedElementField[i]; if (num3 == 0) { if (num5 != 0) { return(ContainmentType.Intersects); } } else { BoundingBoxI xi; bool flag; xi.Min = (Vector3I)(vectori6 + vectori3); Vector3I *vectoriPtr1 = (Vector3I *)ref xi.Min; vectoriPtr1[0] = vectoriPtr1[0] << num3; BoundingBoxI *xiPtr1 = (BoundingBoxI *)ref xi; xiPtr1->Max = (Vector3I)((xi.Min + (1 << (num3 & 0x1f))) - 1); Vector3I.Max(ref xi.Min, ref min, out xi.Min); Vector3I.Min(ref xi.Max, ref max, out xi.Max); ((BoundingBoxI *)ref xi).Intersects(ref xi, out flag); if (flag) { return(ContainmentType.Intersects); } } } } } } return(disjoint); }
internal void UpdateAfterSimulation10() { this.UpdateRigidBodyShape(); if (this.m_voxelMap.Storage != null) { foreach (IMyEntity entity in this.m_nearbyEntities) { if (entity != null) { bool flag = false; MyPhysicsBody physics = entity.Physics as MyPhysicsBody; if (((physics != null) && (physics.RigidBody != null)) && ((physics.RigidBody.Layer == 0x17) || (physics.RigidBody.Layer == 10))) { flag = true; } if ((((entity is MyCubeGrid) || flag) && !entity.MarkedForClose) && (entity.Physics != null)) { BoundingBoxD xd; this.GetPrediction(entity, out xd); if (xd.Intersects(this.m_voxelMap.PositionComp.WorldAABB)) { Vector3I vectori; Vector3I vectori2; HkUniformGridShape shape; int num1; if (flag || !UseLod1VoxelPhysics) { num1 = 0; } else { num1 = 1; } int lod = num1; int num2 = 1 << (lod & 0x1f); BoundingBoxD xd2 = xd.TransformFast(this.m_voxelMap.PositionComp.WorldMatrixInvScaled); xd2.Translate(this.m_voxelMap.SizeInMetresHalf); Vector3 max = (Vector3)xd2.Max; Vector3 min = (Vector3)xd2.Min; this.ClampVoxelCoords(ref min, ref max, out vectori, out vectori2); vectori = vectori >> lod; vectori2 = vectori2 >> lod; int size = ((vectori2 - vectori) + 1).Size; if (size >= m_cellsToGenerateBuffer.Length) { m_cellsToGenerateBuffer = new Vector3I[MathHelper.GetNearestBiggerPowerOfTwo(size)]; } if (this.GetShape(lod, out shape)) { if (shape.Base.IsZero) { MyAnalyticsHelper.ReportBug("Null voxel shape", "SE-7366", true, @"E:\Repo1\Sources\Sandbox.Game\Engine\Voxels\MyVoxelPhysicsBody.cs", 680); } else { int requiredCellsCount = shape.GetMissingCellsInRange(ref vectori, ref vectori2, m_cellsToGenerateBuffer); if (requiredCellsCount != 0) { BoundingBoxI box = new BoundingBoxI((vectori * 8) * num2, (Vector3I)(((vectori2 + 1) * 8) * num2)); box.Translate(this.m_voxelMap.StorageMin); if ((requiredCellsCount > 0) && (this.m_voxelMap.Storage.Intersect(ref box, lod, true) != ContainmentType.Intersects)) { this.SetEmptyShapes(lod, ref shape, requiredCellsCount); } else { for (int i = 0; i < requiredCellsCount; i++) { this.StartPrecalcJobPhysicsIfNeeded(lod, i); } } } } } } } } } this.ScheduleBatchJobs(); if (this.m_bodiesInitialized) { this.CheckAndDiscardShapes(); } } }
public ContainmentType Intersect(ref BoundingBoxI box, bool lazy = false) { return m_provider.Intersect(box, lazy); }
private void Process(CommandFeedback feedback, IMyCubeGrid grid) { if (grid.CustomName == null || !grid.CustomName.StartsWithICase("EqProcBuild")) { return; } var ob = grid.GetObjectBuilder(true) as MyObjectBuilder_CubeGrid; if (ob == null) { return; } this.Info("Begin processing {0}", grid.CustomName); feedback?.Invoke("Processing {0}", grid.CustomName); try { var dummyDel = new List <MyTuple <MyObjectBuilder_CubeBlock, string> >(); var blockKeep = new List <MyObjectBuilder_CubeBlock>(); var blockMap = new Dictionary <Vector3I, MyObjectBuilder_CubeBlock>(Vector3I.Comparer); foreach (var block in ob.CubeBlocks) { var mount = false; foreach (var name in block.ConfigNames()) { if (!name.StartsWithICase(MountDelegated) && !name.StartsWithICase(ReservedSpaceDelegated)) { continue; } dummyDel.Add(MyTuple.Create(block, name)); mount = true; break; } if (mount) { continue; } var blockMin = (Vector3I)block.Min; Vector3I blockMax; BlockTransformations.ComputeBlockMax(block, out blockMax); for (var rangeItr = new Vector3I_RangeIterator(ref blockMin, ref blockMax); rangeItr.IsValid(); rangeItr.MoveNext()) { blockMap[rangeItr.Current] = block; } blockKeep.Add(block); } this.Info("Found {0} blocks to keep, {1} block mounts to remap", blockKeep.Count, dummyDel.Count); foreach (var pair in dummyDel) { var block = pair.Item1; var useName = pair.Item2; IEnumerable <Base6Directions.Direction> dirs = Base6Directions.EnumDirections; var def = MyDefinitionManager.Static.GetCubeBlockDefinition(pair.Item1); var transform = new MatrixI(block.BlockOrientation); if (def?.MountPoints != null) { var mountDirs = new HashSet <Base6Directions.Direction>(); foreach (var mount in def.MountPoints) { mountDirs.Add(Base6Directions.GetDirection(Vector3I.TransformNormal(mount.Normal, ref transform))); } } var args = useName.Split(' '); var keepArgs = new List <string>(args.Length); foreach (var arg in args) { if (arg.StartsWithICase(PartDummyUtils.ArgumentMountDirection)) { Base6Directions.Direction dir; if (Enum.TryParse(arg.Substring(2), out dir)) { dirs = new[] { transform.GetDirection(Base6Directions.GetOppositeDirection(dir)) } } ; else { this.Error("Failed to parse direction argument \"{0}\"", arg); feedback?.Invoke("Error: Failed to parse direction argument \"{0}\"", arg); } } else { keepArgs.Add(arg); } } useName = string.Join(" ", keepArgs); MyObjectBuilder_CubeBlock outputBlock = null; var outputDir = Base6Directions.Direction.Forward; foreach (var dir in dirs) { MyObjectBuilder_CubeBlock tmp; if (!blockMap.TryGetValue(block.Min + Base6Directions.GetIntVector(dir), out tmp)) { continue; } if (tmp.ConfigNames().Any(x => x.StartsWithICase(MountDelegated))) { continue; } if (outputBlock != null) { this.Error("Multiple directions found for {0}", pair.Item2); feedback?.Invoke("Error: Multiple directions found for {0}", pair.Item2); } outputBlock = tmp; outputDir = dir; } if (outputBlock == null || !ApplyDelegate(ob, block, useName, outputBlock, outputDir)) { this.Error("Failed to find delegated mount point for {0}", pair.Item2); feedback?.Invoke("Error: Failed to find delegated mount point for {0}", pair.Item2); } } ob.CubeBlocks = blockKeep; // Grab related grids! var relatedGrids = new HashSet <IMyCubeGrid> { grid }; var scanRelated = new Queue <IMyCubeGrid>(); var relatedGridController = new Dictionary <IMyCubeGrid, IMyCubeBlock>(); scanRelated.Enqueue(grid); while (scanRelated.Count > 0) { var subGrid = scanRelated.Dequeue(); IMyCubeBlock controllerForThisGrid = null; relatedGridController.TryGetValue(subGrid, out controllerForThisGrid); subGrid.GetBlocks(null, (y) => { var x = y?.FatBlock; if (x == null) { return(false); } var childGrid = (x as IMyMechanicalConnectionBlock)?.TopGrid; if (childGrid != null && relatedGrids.Add(childGrid)) { scanRelated.Enqueue(childGrid); relatedGridController[childGrid] = x.CubeGrid == grid ? x : controllerForThisGrid; } var parentGrid = (x as IMyAttachableTopBlock)?.Base?.CubeGrid; // ReSharper disable once InvertIf if (parentGrid != null && relatedGrids.Add(parentGrid)) { scanRelated.Enqueue(parentGrid); relatedGridController[parentGrid] = x.CubeGrid == grid ? x : controllerForThisGrid; } return(false); }); } relatedGrids.Remove(grid); var removedNoController = relatedGrids.RemoveWhere(x => !relatedGridController.ContainsKey(x)); if (removedNoController > 0) { this.Error("Failed to find the mechanical connection block for all subgrids. {0} will be excluded", removedNoController); feedback?.Invoke("Error: Failed to find the mechanical connection block for all subgrids. {0} will be excluded", removedNoController); } // Need to add reserved space for subgrids so they don't overlap. So compute that. Yay! foreach (var rel in relatedGrids) { IMyCubeBlock root; if (!relatedGridController.TryGetValue(rel, out root)) { this.Error("Unable to find the mechanical connection for grid {0}", rel.CustomName); feedback?.Invoke("Error: Unable to find the mechanical connection for grid {0}", rel.CustomName); continue; } MyObjectBuilder_CubeBlock blockDest; if (blockMap.TryGetValue(root.Min, out blockDest)) { var blockLocal = (MatrixD) new MatrixI(blockDest.BlockOrientation).GetFloatMatrix(); blockLocal.Translation = (Vector3I)blockDest.Min * grid.GridSize; var blockWorld = MatrixD.Multiply(blockLocal, grid.WorldMatrix); var worldAABB = rel.WorldAABB; worldAABB = Utilities.TransformBoundingBox(worldAABB, MatrixD.Invert(blockWorld)); var gridAABB = new BoundingBoxI(Vector3I.Floor(worldAABB.Min / grid.GridSize), Vector3I.Ceiling(worldAABB.Max / grid.GridSize)); var code = $"{PartMetadata.ReservedSpacePrefix} NE:{gridAABB.Min.X}:{gridAABB.Min.Y}:{gridAABB.Min.Z} PE:{gridAABB.Max.X}:{gridAABB.Max.Y}:{gridAABB.Max.Z}"; this.Info("Added reserved space for subgrid {0}: Spec is \"{1}\"", rel.CustomName, code); if (blockDest.Name == null || blockDest.Name.Trim().Length == 0) { blockDest.Name = code; } else { blockDest.Name += PartMetadata.MultiUseSentinel + code; } } else { this.Error("Unable to find the OB for grid block {0} ({1}, {2}, {3}). Is it a delegate?", (root as IMyTerminalBlock)?.CustomName ?? root.Name, root.Min.X, root.Min.Y, root.Min.Z); feedback?.Invoke("Unable to the find OB for grid block {0} ({1}, {2}, {3}). Was it a delegate?", (root as IMyTerminalBlock)?.CustomName ?? root.Name, root.Min.X, root.Min.Y, root.Min.Z); } } var allGrids = new List <MyObjectBuilder_CubeGrid>(relatedGrids.Count + 1) { ob }; allGrids.AddRange(relatedGrids.Select(relGrid => relGrid.GetObjectBuilder(false)).OfType <MyObjectBuilder_CubeGrid>()); // Compose description: TODO I'd love if this actually worked :/ // var storage = new MyPartMetadata(); // storage.InitFromGrids(ob, allGrids); // var data = Convert.ToBase64String(MyAPIGateway.Utilities.SerializeToBinary(storage.GetObjectBuilder())); var defOut = new MyObjectBuilder_PrefabDefinition() { Id = new SerializableDefinitionId(typeof(MyObjectBuilder_PrefabDefinition), grid.CustomName), CubeGrids = allGrids.ToArray() }; var fileName = grid.CustomName + ".sbc"; this.Info("Saving {1} grids as {0}", fileName, defOut.CubeGrids.Length); feedback?.Invoke("Saving {1} grids as {0}", fileName, defOut.CubeGrids.Length); var mishMash = new MyObjectBuilder_Definitions() { Prefabs = new MyObjectBuilder_PrefabDefinition[] { defOut } }; var writer = MyAPIGateway.Utilities.WriteBinaryFileInLocalStorage(fileName, typeof(DesignTools)); var obCode = MyAPIGateway.Utilities.SerializeToXML(mishMash); obCode = obCode.Replace("encoding=\"utf-16\"", "encoding=\"utf-8\""); writer.Write(Encoding.UTF8.GetBytes(obCode)); writer.Close(); } catch (Exception e) { this.Error("Failed to parse. Error:\n{0}", e.ToString()); } }
internal void DoClipping(float camDistanceFromCenter, Vector3D localPosition, float farPlaneDistance, RequestCollector collector, bool frustumCulling, float rangeScale) { int lodIndex = m_lodIndex; if (!ShouldBeThisLodVisible(camDistanceFromCenter)) { MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); return; } m_localPosition = localPosition; MyClipmap.ComputeLodViewBounds(m_clipmap.m_scaleGroup, lodIndex, out m_nearDistance, out m_farDistance); farPlaneDistance *= rangeScale; m_farDistance *= rangeScale; m_nearDistance *= rangeScale; m_fitsInFrustum = (farPlaneDistance * 1.25f) > m_nearDistance; if (!m_fitsInFrustum && m_lodIndex == lodIndex) return; //var localFrustum = new BoundingFrustumD(CameraFrustumGetter().Matrix * m_parent.m_invWorldMatrix); var frustum = CameraFrustumGetter(); Vector3I min, max; // Vector3I ignoreMin, ignoreMax; var minD = m_localPosition - (double)m_farDistance; var maxD = m_localPosition + (double)m_farDistance; MyVoxelCoordSystems.LocalPositionToRenderCellCoord(lodIndex, ref minD, out min); MyVoxelCoordSystems.LocalPositionToRenderCellCoord(lodIndex, ref maxD, out max); BoundingBoxI lodBox = new BoundingBoxI(Vector3I.Zero, Vector3I.Max(m_lodSizeMinusOne, Vector3I.Zero)); 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; intersection.IntersectWith(ref 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. if (frustumCulling) { MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); } if (intersects) { float sizeInMetres = MyVoxelCoordSystems.RenderCellSizeInMeters(lodIndex); MyCellCoord cell = new MyCellCoord(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 (frustumCulling) //{ // 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) // { // m_outsideCells.Add(cell.CoordInLod); // continue; // } //} UnclipCell(collector, cell, true); } //cache cells around frustum if (collector.SentRequestsEmpty) { foreach (var outsideCell in m_outsideCells) { cell.CoordInLod = outsideCell; UnclipCell(collector, cell, frustumCulling); } } m_outsideCells.Clear(); } }
private bool ApplyDelegate(MyObjectBuilder_CubeGrid grid, MyObjectBuilder_CubeBlock source, string srcName, MyObjectBuilder_CubeBlock dest, Base6Directions.Direction destDir) { if (srcName.StartsWithICase(MountDelegated)) { var lTransOrig = new MatrixI(source.BlockOrientation); var lTrans = new MatrixI(dest.BlockOrientation); MatrixI iTrans; MatrixI.Invert(ref lTrans, out iTrans); var arguments = PartDummyUtils.ConfigArguments(srcName.Substring(MountDelegated.Length).Trim()).Select( (arg) => { if (arg.StartsWithICase(PartDummyUtils.ArgumentBiasDirection)) { Base6Directions.Direction dir; if (Enum.TryParse(arg.Substring(PartDummyUtils.ArgumentBiasDirection.Length), out dir)) { return(PartDummyUtils.ArgumentBiasDirection + iTrans.GetDirection(lTransOrig.GetDirection(dir))); } else { this.Error("Failed to parse bias argument \"{0}\"", arg); } } else if (arg.StartsWithICase(PartDummyUtils.ArgumentSecondBiasDirection)) { Base6Directions.Direction dir; if (Enum.TryParse(arg.Substring(PartDummyUtils.ArgumentSecondBiasDirection.Length), out dir)) { return(PartDummyUtils.ArgumentSecondBiasDirection + iTrans.GetDirection(lTransOrig.GetDirection(dir))); } else { this.Error("Failed to parse second bias argument \"{0}\"", arg); } } return(arg); }).ToList(); arguments.Add(PartDummyUtils.ArgumentMountDirection + iTrans.GetDirection(Base6Directions.GetOppositeDirection(destDir))); var anchorPoint = source.Min + Base6Directions.GetIntVector(destDir); var del = anchorPoint - dest.Min; if (del != Vector3I.Zero) { arguments.Add(PartDummyUtils.ArgumentAnchorPoint + del.X + ":" + del.Y + ":" + del.Z); } var outName = PartMetadata.MountPrefix + " " + string.Join(" ", arguments); if (string.IsNullOrWhiteSpace(dest.Name)) { dest.Name = outName; } else { dest.Name = dest.Name + PartMetadata.MultiUseSentinel + outName; } return(true); } if (srcName.StartsWithICase(ReservedSpaceDelegated)) { var baseName = srcName.Substring(ReservedSpaceDelegated.Length).Trim(); var args = baseName.Split(' ').Select(x => x.Trim()).Where(x => x.Length > 0).ToArray(); var box = PartDummyUtils.ParseReservedSpace(MyDefinitionManager.Static.GetCubeSize(grid.GridSizeEnum), source, args, this.Error); var del = source.Min - (Vector3I)dest.Min; box.Box.Max += del; box.Box.Min += del; var boxLocalFloat = Utilities.TransformBoundingBox(box.Box, Matrix.Invert(new MatrixI(dest.BlockOrientation).GetFloatMatrix())); var boxLocal = new BoundingBoxI(Vector3I.Floor(boxLocalFloat.Min), Vector3I.Ceiling(boxLocalFloat.Max)); var outName = $"{PartMetadata.ReservedSpacePrefix} NE:{boxLocal.Min.X}:{boxLocal.Min.Y}:{boxLocal.Min.Z} PE:{boxLocal.Max.X}:{boxLocal.Max.Y}:{boxLocal.Max.Z}"; if (box.IsShared) { outName += " shared"; } if (box.IsOptional) { outName += " optional"; } if (string.IsNullOrWhiteSpace(dest.Name)) { dest.Name = outName; } else { dest.Name = dest.Name + PartMetadata.MultiUseSentinel + outName; } return(true); } return(false); }
public static BoundingBoxD ToBoundingBoxD(this BoundingBoxI box) { return(new BoundingBoxD(box.Min, box.Max)); }
public ContainmentType Intersect(BoundingBoxI box, bool lazy) { ContainmentType ct = ContainmentType.Disjoint; BoundingBox bb = new BoundingBox(box); BoundingSphere sp = new BoundingSphere(bb.Center, bb.Extents.Length() / 2f); // Check filled shapes. foreach (var shape in m_data.FilledShapes) { var c = shape.Contains(ref bb, ref sp, 1f); if (c == ContainmentType.Contains) ct = c; else if (c == ContainmentType.Intersects && ct == ContainmentType.Disjoint) ct = c; } // Check shapes removed, we don't check how they are removed so we only discard if the removed shape covers the whole bb. if (ct != ContainmentType.Disjoint) { foreach (var shape in m_data.RemovedShapes) { var c = shape.Contains(ref bb, ref sp, 1f); if (c == ContainmentType.Contains) { ct = ContainmentType.Disjoint; break; } else if (c == ContainmentType.Intersects) { ct = ContainmentType.Intersects; } } } return ct; }
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); } } }
// Iterate over sector boxes in a range. private void ForEachSector(Vector3 localPosition, float range, SectorIteration iterator) { Vector3 sectorPosition; LocalPositionToSectorCube(localPosition, out sectorPosition); Vector3D referencePoint = localPosition; SectorScans.Hit(); Vector3 rangev = new Vector3(range); BoundingBox probe = new BoundingBox(sectorPosition - rangev, sectorPosition + rangev); BoundingBoxI inter = m_sectorBox.Intersect(probe); Vector3S min = new Vector3S(inter.Min); Vector3S max = new Vector3S(inter.Max); // Iterate over each face of the cube that is in the intersection. MyPlanetSectorId id = new MyPlanetSectorId(); // Front if (inter.Min.Z == m_sectorBox.Min.Z) { id.Direction = Vector3B.Backward; id.Position.Z = min.Z; for (id.Position.X = min.X; id.Position.X <= max.X; id.Position.X++) { for (id.Position.Y = min.Y; id.Position.Y <= max.Y; id.Position.Y++) { iterator(this, ref id, ref referencePoint); } } } // Back if (inter.Max.Z == m_sectorBox.Max.Z) { id.Direction = Vector3B.Forward; id.Position.Z = max.Z; for (id.Position.X = min.X; id.Position.X <= max.X; id.Position.X++) { for (id.Position.Y = min.Y; id.Position.Y <= max.Y; id.Position.Y++) { iterator(this, ref id, ref referencePoint); } } } // Right if (inter.Min.X == m_sectorBox.Min.X) { id.Direction = Vector3B.Right; id.Position.X = min.X; for (id.Position.Y = min.Y; id.Position.Y <= max.Y; id.Position.Y++) { for (id.Position.Z = min.Z; id.Position.Z <= max.Z; id.Position.Z++) { iterator(this, ref id, ref referencePoint); } } } // Left if (inter.Max.X == m_sectorBox.Max.X) { id.Direction = Vector3B.Left; id.Position.X = max.X; for (id.Position.Y = min.Y; id.Position.Y <= max.Y; id.Position.Y++) { for (id.Position.Z = min.Z; id.Position.Z <= max.Z; id.Position.Z++) { iterator(this, ref id, ref referencePoint); } } } // Up if (inter.Min.Y == m_sectorBox.Min.Y) { id.Direction = Vector3B.Up; id.Position.Y = min.Y; for (id.Position.X = min.X; id.Position.X <= max.X; id.Position.X++) { for (id.Position.Z = min.Z; id.Position.Z <= max.Z; id.Position.Z++) { iterator(this, ref id, ref referencePoint); } } } // Down if (inter.Max.Y == m_sectorBox.Max.Y) { id.Direction = Vector3B.Down; id.Position.Y = max.Y; for (id.Position.X = min.X; id.Position.X <= max.X; id.Position.X++) { for (id.Position.Z = min.Z; id.Position.Z <= max.Z; id.Position.Z++) { iterator(this, ref id, ref referencePoint); } } } }
internal unsafe void InvalidateRange(Vector3I minVoxelChanged, Vector3I maxVoxelChanged, int lod) { if (this.m_bodiesInitialized) { if (this.m_queueInvalidation) { if (this.m_queuedRange.Max.X < 0) { this.m_queuedRange = new BoundingBoxI(minVoxelChanged, maxVoxelChanged); } else { BoundingBoxI box = new BoundingBoxI(minVoxelChanged, maxVoxelChanged); this.m_queuedRange.Include(ref box); } } else { Vector3I vectori; Vector3I vectori2; minVoxelChanged -= 2; maxVoxelChanged = (Vector3I)(maxVoxelChanged + 1); this.m_voxelMap.Storage.ClampVoxelCoord(ref minVoxelChanged, 1); this.m_voxelMap.Storage.ClampVoxelCoord(ref maxVoxelChanged, 1); MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref minVoxelChanged, out vectori); MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxVoxelChanged, out vectori2); Vector3I minChanged = (vectori - this.m_cellsOffset) >> lod; Vector3I result = (vectori2 - this.m_cellsOffset) >> lod; Vector3I geometryCellCoord = this.m_voxelMap.Size - 1; Vector3I *vectoriPtr1 = (Vector3I *)ref geometryCellCoord; MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref (Vector3I) ref vectoriPtr1, out geometryCellCoord); geometryCellCoord = geometryCellCoord >> lod; Vector3I *vectoriPtr2 = (Vector3I *)ref result; Vector3I.Min(ref (Vector3I) ref vectoriPtr2, ref geometryCellCoord, out result); HkRigidBody rigidBody = this.GetRigidBody(lod); if ((minChanged == Vector3I.Zero) && (result == geometryCellCoord)) { this.m_workTracker.CancelAll(); } else { using (MyUtils.ReuseCollection <MyCellCoord>(ref m_toBeCancelledCache)) { BoundingBoxI xi2 = new BoundingBoxI(vectori, vectori2); foreach (KeyValuePair <MyCellCoord, MyPrecalcJobPhysicsPrefetch> pair in this.m_workTracker) { if (xi2.Contains(pair.Key.CoordInLod) != ContainmentType.Disjoint) { m_toBeCancelledCache.Add(pair.Key); } } foreach (MyCellCoord coord in m_toBeCancelledCache) { this.m_workTracker.CancelIfStarted(coord); } } } if (rigidBody != null) { HkUniformGridShape shape = (HkUniformGridShape)rigidBody.GetShape(); int size = ((result - minChanged) + 1).Size; if (size >= m_cellsToGenerateBuffer.Length) { m_cellsToGenerateBuffer = new Vector3I[MathHelper.GetNearestBiggerPowerOfTwo(size)]; } int num2 = shape.InvalidateRange(ref minChanged, ref result, m_cellsToGenerateBuffer); for (int i = 0; i < num2; i++) { this.StartPrecalcJobPhysicsIfNeeded(lod, i); } } this.m_voxelMap.RaisePhysicsChanged(); } } }
public bool GetBlockStates(Dictionary <Vector3I, BlockState> blockStates, long projectorId, int subgridIndex, BoundingBoxI box, int mask) { return((bool)(_miGetBlockStates?.Invoke(Api, new object[] { blockStates, projectorId, subgridIndex, box, mask }) ?? false)); }
public override unsafe ContainmentType IntersectInternal(ref BoundingBox box, bool lazy) { int stackIdx = 0; int stackSize = MySparseOctree.EstimateStackSize(m_treeHeight); MyCellCoord* stack = stackalloc MyCellCoord[stackSize]; MyCellCoord data = new MyCellCoord(m_treeHeight + LeafLodCount, ref Vector3I.Zero); stack[stackIdx++] = data; MyCellCoord cell = new MyCellCoord(); BoundingBoxI bb = new BoundingBoxI(new Vector3I(box.Min), new Vector3I(Vector3.Ceiling(box.Max))); const ContainmentType invalid = (ContainmentType)(-1); ContainmentType inter = invalid; while (stackIdx > 0) { Debug.Assert(stackIdx <= stackSize); data = stack[--stackIdx]; cell.Lod = Math.Max(data.Lod - LeafLodCount, 0); cell.CoordInLod = data.CoordInLod; int lodDiff; IMyOctreeLeafNode leaf; if (m_contentLeaves.TryGetValue(cell.PackId64(), out leaf)) { lodDiff = data.Lod; var rangeMinInDataLod = bb.Min >> lodDiff; var rangeMaxInDataLod = bb.Max >> lodDiff; if (data.CoordInLod.IsInsideInclusive(ref rangeMinInDataLod, ref rangeMaxInDataLod)) { var leafMin = cell.CoordInLod << lodDiff; BoundingBoxI localBox = new BoundingBoxI(leafMin, leafMin + (1 << lodDiff)); localBox.IntersectWith(ref bb); var lint = leaf.Intersect(ref localBox); if (inter == invalid) inter = lint; if (lint == ContainmentType.Intersects) return ContainmentType.Intersects; if (lint != inter || (inter == ContainmentType.Contains && lazy)) return ContainmentType.Intersects; } continue; } cell.Lod -= 1; lodDiff = data.Lod - 1; var node = m_contentNodes[cell.PackId64()]; var min = bb.Min >> lodDiff; var max = bb.Max >> 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 (data.Lod == 0) { //if(node.AllDataSame(0)) return return ContainmentType.Intersects; } else if (node.HasChild(i)) { Debug.Assert(stackIdx < stackSize); stack[stackIdx++] = new MyCellCoord(data.Lod - 1, nodePositionInChild + childPosRelative); } } } if (inter == invalid) inter = ContainmentType.Disjoint; return inter; }
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(); }
public ContainmentType Intersect(ref BoundingBoxI box, bool lazy) { BoundingBoxI localCoords = box; localCoords.Translate(-m_voxelRangeMin); return m_octree.Intersect(ref localCoords, lazy); }
internal void DoClipping(float camDistanceFromCenter, Vector3D localPosition, float farPlaneDistance, RequestCollector collector, bool frustumCulling, float rangeScale) { int lodIndex = m_lodIndex; if (!ShouldBeThisLodVisible(camDistanceFromCenter)) { MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); return; } m_localPosition = localPosition; MyClipmap.ComputeLodViewBounds(m_clipmap.m_scaleGroup, lodIndex, out m_nearDistance, out m_farDistance); farPlaneDistance *= rangeScale; m_farDistance *= rangeScale; m_nearDistance *= rangeScale; m_fitsInFrustum = (farPlaneDistance * 1.25f) > m_nearDistance; if (!m_fitsInFrustum && m_lodIndex == lodIndex) { 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(lodIndex, ref minD, out min); MyVoxelCoordSystems.LocalPositionToRenderCellCoord(lodIndex, ref maxD, out max); BoundingBoxI lodBox = new BoundingBoxI(Vector3I.Zero, Vector3I.Max(m_lodSizeMinusOne, Vector3I.Zero)); 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; intersection.IntersectWith(ref 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. if (frustumCulling) { MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); } if (intersects) { float sizeInMetres = MyVoxelCoordSystems.RenderCellSizeInMeters(lodIndex); MyCellCoord cell = new MyCellCoord(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 (frustumCulling) //{ // 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) // { // m_outsideCells.Add(cell.CoordInLod); // continue; // } //} UnclipCell(collector, cell, true); } //cache cells around frustum if (collector.SentRequestsEmpty) { foreach (var outsideCell in m_outsideCells) { cell.CoordInLod = outsideCell; UnclipCell(collector, cell, frustumCulling); } } m_outsideCells.Clear(); } }
public bool GetBlockStates(Dictionary <Vector3I, BlockState> blockStates, long projectorId, int subgridIndex, BoundingBoxI box, int mask) { if (!Available) { return(false); } var blockIntStates = new Dictionary <Vector3I, int>(); var fn = (Func <Dictionary <Vector3I, int>, long, int, BoundingBoxI, int, bool>)api[6]; if (!fn(blockIntStates, projectorId, subgridIndex, box, mask)) { return(false); } foreach (var pair in blockIntStates) { blockStates[pair.Key] = (BlockState)pair.Value; } return(true); }
private void MergeAsteroidMaterialFrom(ref MyVoxelMap newAsteroid, Vector3 min, StructureVoxelModel modelPrimary, StructureVoxelModel modelSecondary, Vector3 minPrimary, Vector3 minSecondary) { var filenameSecondary = modelSecondary.SourceVoxelFilepath ?? modelSecondary.VoxelFilepath; var filenamePrimary = modelPrimary.SourceVoxelFilepath ?? modelPrimary.VoxelFilepath; Vector3I block; Vector3I newBlock; Vector3I cacheSize; var asteroid = new MyVoxelMap(); asteroid.Load(filenamePrimary); BoundingBoxI content = modelPrimary.InflatedContentBounds; for (block.Z = content.Min.Z; block.Z <= content.Max.Z; block.Z += 64) { for (block.Y = content.Min.Y; block.Y <= content.Max.Y; block.Y += 64) { for (block.X = content.Min.X; block.X <= content.Max.X; block.X += 64) { var cache = new MyStorageData(); cacheSize = new Vector3I(MathHelper.Min(content.Max.X, block.X + 63) - block.X + 1, MathHelper.Min(content.Max.Y, block.Y + 63) - block.Y + 1, MathHelper.Min(content.Max.Z, block.Z + 63) - block.Z + 1); cache.Resize(cacheSize); asteroid.Storage.ReadRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, block, block + cacheSize - 1); newBlock = ((minPrimary - min) + (Vector3D)(block - content.Min)).RoundToVector3I(); newAsteroid.Storage.WriteRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, newBlock, newBlock + cacheSize - 1); } } } asteroid.Load(filenameSecondary); content = modelSecondary.InflatedContentBounds; for (block.Z = content.Min.Z; block.Z <= content.Max.Z; block.Z += 64) { for (block.Y = content.Min.Y; block.Y <= content.Max.Y; block.Y += 64) { for (block.X = content.Min.X; block.X <= content.Max.X; block.X += 64) { var cache = new MyStorageData(); cacheSize = new Vector3I(MathHelper.Min(content.Max.X, block.X + 63) - block.X + 1, MathHelper.Min(content.Max.Y, block.Y + 63) - block.Y + 1, MathHelper.Min(content.Max.Z, block.Z + 63) - block.Z + 1); cache.Resize(cacheSize); asteroid.Storage.ReadRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, block, block + cacheSize - 1); newBlock = ((minSecondary - min) + (Vector3D)(block - content.Min)).RoundToVector3I(); var newCache = new MyStorageData(); newCache.Resize(cacheSize); newAsteroid.Storage.ReadRange(newCache, MyStorageDataTypeFlags.ContentAndMaterial, 0, newBlock, newBlock + cacheSize - 1); Vector3I p; for (p.Z = 0; p.Z < cacheSize.Z; ++p.Z) { for (p.Y = 0; p.Y < cacheSize.Y; ++p.Y) { for (p.X = 0; p.X < cacheSize.X; ++p.X) { byte volume = cache.Content(ref p); byte material = cache.Material(ref p); if (volume > 0) { newCache.Material(ref p, material); } } } } newAsteroid.Storage.WriteRange(newCache, MyStorageDataTypeFlags.ContentAndMaterial, newBlock, newBlock + cacheSize - 1); } } } }
public ContainmentType Intersect(ref BoundingBoxI box, bool lazy = false) { return(m_provider.Intersect(box, lazy)); }
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(); }
public static ContainmentType Intersect(this VRage.Game.Voxels.IMyStorage self, ref BoundingBox box, bool lazy = true) { BoundingBoxI xi = new BoundingBoxI(box); return(self.Intersect(ref xi, 0, lazy)); }