private void storage_RangeChangedPlanet(Vector3I minChanged, Vector3I maxChanged, MyStorageDataTypeFlags dataChanged) { ProfilerShort.Begin("MyVoxelMap::storage_RangeChanged"); Vector3I minSector = minChanged / PHYSICS_SECTOR_SIZE_METERS; Vector3I maxSector = maxChanged / PHYSICS_SECTOR_SIZE_METERS; MyVoxelPhysics voxelMap; if (m_physicsShapes != null) { for (var it = new Vector3I.RangeIterator(ref minSector, ref maxSector); it.IsValid(); it.MoveNext()) { if (m_physicsShapes.TryGetValue(it.Current, out voxelMap)) { if (voxelMap != null) { voxelMap.OnStorageChanged(minChanged, maxChanged, dataChanged); } } } } if (Render is MyRenderComponentVoxelMap) { (Render as MyRenderComponentVoxelMap).InvalidateRange(minChanged, maxChanged); } OnRangeChanged(minChanged, maxChanged, dataChanged); ProfilerShort.End(); }
private int GetDivideIndex(ref Vector3I renderCellCoord) { // TODO: Optimize int divideIndex = 0; if (m_lodDivisions > 1) { BoundingBoxD lodAabb = m_boundingBoxes.GetAabb(m_boundingBoxes.GetRoot()); Vector3I test = Vector3I.Round(lodAabb.Size / (double)MyVoxelCoordSystems.RenderCellSizeInMeters(m_lod)); //Vector3I lodSizeMinusOne = m_parentClipmap.LodSizeMinusOne(m_lod); //Vector3I lodSize = lodSizeMinusOne + Vector3I.One; Vector3I lodSize = test; Vector3I lodSizeMinusOne = test - 1; Vector3I lodDivision = Vector3I.One * (m_lodDivisions - 1); var cellIterator = new Vector3I.RangeIterator(ref Vector3I.Zero, ref lodDivision); for (; cellIterator.IsValid(); cellIterator.MoveNext()) { Vector3I currentDivision = cellIterator.Current; Vector3I min = currentDivision * lodSize / m_lodDivisions; Vector3I max = (currentDivision + Vector3I.One) * lodSize / m_lodDivisions; if (renderCellCoord.IsInsideInclusive(ref min, ref max)) { break; } } Debug.Assert(cellIterator.IsValid(), "Valid division index not found!"); Vector3I foundCell = cellIterator.Current; divideIndex = GetDivideIndexFromMergeCell(ref foundCell); } return(divideIndex); }
public void PrefetchShapeOnRay(ref LineD ray) { Vector3I minCorner, maxCorner; MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref ray.From, out minCorner); MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref ray.To, out maxCorner); minCorner /= PHYSICS_SECTOR_SIZE_METERS; maxCorner /= PHYSICS_SECTOR_SIZE_METERS; for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext()) { if (m_physicsShapes.ContainsKey(it.Current)) { m_physicsShapes[it.Current].PrefetchShapeOnRay(ref ray); } } }
private void storage_RangeChangedPlanet(Vector3I minChanged, Vector3I maxChanged, MyStorageDataTypeFlags dataChanged) { ProfilerShort.Begin("MyVoxelMap::storage_RangeChanged"); Vector3I minSector = minChanged / PHYSICS_SECTOR_SIZE_METERS; Vector3I maxSector = maxChanged / PHYSICS_SECTOR_SIZE_METERS; Vector3I increment = m_storage.Size / (m_numCells + 1); for (var it = new Vector3I.RangeIterator(ref minSector, ref maxSector); it.IsValid(); it.MoveNext()) { MyVoxelPhysics voxelMap = CreatePhysicsShape(ref increment, ref it); voxelMap.OnStorageChanged(minChanged, maxChanged, dataChanged); } if (Render is MyRenderComponentVoxelMap) { (Render as MyRenderComponentVoxelMap).InvalidateRange(minChanged, maxChanged); } ProfilerShort.End(); }
private bool FindFirstAcceptableEntry() { while (true) { while (m_storageIndex != -1) { Entry current = m_parent.m_storage[m_storageIndex]; if ((current.Point - m_point).LengthSquared() < m_distSq) { return(true); } m_previousIndex = m_storageIndex; m_storageIndex = current.NextEntry; } m_rangeIterator.MoveNext(); if (!FindNextNonemptyBin()) { return(false); } } }
private void GeneratePhysicalShapeForBox(ref Vector3I increment, ref BoundingBoxD shapeBox) { if (!shapeBox.Intersects(PositionComp.WorldAABB)) { return; } Vector3I minCorner, maxCorner; MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref shapeBox.Min, out minCorner); MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref shapeBox.Max, out maxCorner); minCorner /= PHYSICS_SECTOR_SIZE_METERS; maxCorner /= PHYSICS_SECTOR_SIZE_METERS; for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext()) { ProfilerShort.Begin("Myplanet::create physics shape"); CreatePhysicsShape(ref increment, ref it); ProfilerShort.End(); } }
private void GeneratePhysicalShapeForBox(ref Vector3I increment, ref BoundingBoxD shapeBox) { if (!shapeBox.Intersects(PositionComp.WorldAABB)) return; Vector3I minCorner, maxCorner; MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref shapeBox.Min, out minCorner); MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref shapeBox.Max, out maxCorner); minCorner /= PHYSICS_SECTOR_SIZE_METERS; maxCorner /= PHYSICS_SECTOR_SIZE_METERS; for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext()) { ProfilerShort.Begin("Myplanet::create physics shape"); CreatePhysicsShape(ref increment, ref it); ProfilerShort.End(); } }
private void storage_RangeChangedPlanet(Vector3I minChanged, Vector3I maxChanged, MyStorageDataTypeFlags dataChanged) { ProfilerShort.Begin("MyVoxelMap::storage_RangeChanged"); Vector3I minSector = minChanged / PHYSICS_SECTOR_SIZE_METERS; Vector3I maxSector = maxChanged/PHYSICS_SECTOR_SIZE_METERS; Vector3I increment = m_storage.Size / (m_numCells+1); for (var it = new Vector3I.RangeIterator(ref minSector, ref maxSector); it.IsValid(); it.MoveNext()) { MyVoxelPhysics voxelMap = CreatePhysicsShape(ref increment, ref it); voxelMap.OnStorageChanged(minChanged, maxChanged, dataChanged); } if (Render is MyRenderComponentVoxelMap) { (Render as MyRenderComponentVoxelMap).InvalidateRange(minChanged, maxChanged); } ProfilerShort.End(); }
public static void CutOutShapeWithProperties( MyVoxelBase voxelMap, MyShape shape, out float voxelsCountInPercent, out MyVoxelMaterialDefinition voxelMaterial, Dictionary<MyVoxelMaterialDefinition, int> exactCutOutMaterials = null, bool updateSync = false, bool onlyCheck = false) { if (MySession.Static.EnableVoxelDestruction == false) { voxelsCountInPercent = 0; voxelMaterial = null; return; } ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()"); int originalSum = 0; int removedSum = 0; // Some shapes just ignore transforms so we round the bbox conservativelly by converting it to sphere var bbox = shape.GetWorldBoundaries(); var center = bbox.Center; var radius = (center - bbox.Min).Length(); MatrixD mat = voxelMap.PositionComp.WorldMatrix; MatrixD inverse; //Vector3D translation = mat.Translation; //mat.Translation = Vector3D.Zero; // invert is used to bring voxel coordinates back to world. inverse = voxelMap.PositionComp.WorldMatrixInvScaled;//MatrixD.Invert(ref mat, out inverse); Vector3 offset = voxelMap.StorageMin + voxelMap.SizeInMetresHalf; Vector3D.Transform(ref center, ref inverse, out center); // The transform is centered, but the code expects voxel local coordinates. center += voxelMap.SizeInMetresHalf; bbox = new BoundingBoxD(center - radius, center + radius); Vector3I minCorner, maxCorner; ComputeShapeBounds(voxelMap, ref bbox, Vector3.Zero, voxelMap.Storage.Size, out minCorner, out maxCorner); var cacheMin = minCorner - 1; var cacheMax = maxCorner + 1; voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); m_cache.Resize(cacheMin, cacheMax); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cacheMin, ref cacheMax); { var shapeCenter = bbox.Center; Vector3I exactCenter; MyVoxelCoordSystems.WorldPositionToVoxelCoord(Vector3.Zero, ref shapeCenter, out exactCenter); exactCenter -= cacheMin; exactCenter = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1); voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter)); } ProfilerShort.Begin("Main loop"); for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cacheMin; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove continue; Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToLocalPosition(ref it.Current, out vpos); // center vpos -= offset; // transform back to world space. Vector3D.Transform(ref vpos, ref mat, out vpos); var volume = shape.GetVolume(ref vpos); if (volume == 0f) // if there is no intersection continue; var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); var voxelMat = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref relPos)); var toRemove = (int)(maxRemove * voxelMat.DamageRatio); var newVal = MathHelper.Clamp(original - toRemove, 0, original-maxRemove); var removed = Math.Abs(original - newVal); if (!onlyCheck) m_cache.Content(ref relPos, (byte)newVal); originalSum += original; removedSum += removed; if (exactCutOutMaterials != null) { int value = 0; exactCutOutMaterials.TryGetValue(voxelMat, out value); value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed); exactCutOutMaterials[voxelMat] = value; } } if (removedSum > 0 && updateSync && Sync.IsServer) { shape.SendDrillCutOutRequest(voxelMap); } ProfilerShort.BeginNextBlock("Write"); if (removedSum > 0 && !onlyCheck) { // Clear all small voxel that may have been created during explosion. They can be created even outside the range of // explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the // explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we // will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove // B voxels too. //!! TODO AR & MK : check if this is needed !! RemoveSmallVoxelsUsingChachedVoxels(); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax); } ProfilerShort.End(); voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f; if (removedSum > 0) CheckNeighbourStaticGridsAfterVoxelChanged(MyVoxelBase.OperationType.Cut, voxelMap, shape); ProfilerShort.End(); }
private void storage_RangeChangedPlanet(Vector3I minChanged, Vector3I maxChanged, MyStorageDataTypeFlags dataChanged) { ProfilerShort.Begin("MyVoxelMap::storage_RangeChanged"); Vector3I minSector = minChanged / PHYSICS_SECTOR_SIZE_METERS; Vector3I maxSector = maxChanged / PHYSICS_SECTOR_SIZE_METERS; MyVoxelPhysics voxelMap; if (m_physicsShapes != null) { for (var it = new Vector3I.RangeIterator(ref minSector, ref maxSector); it.IsValid(); it.MoveNext()) { if (m_physicsShapes.TryGetValue(it.Current, out voxelMap)) { if (voxelMap != null) voxelMap.OnStorageChanged(minChanged, maxChanged, dataChanged); } } } if (Render is MyRenderComponentVoxelMap) { (Render as MyRenderComponentVoxelMap).InvalidateRange(minChanged, maxChanged); } OnRangeChanged(minChanged, maxChanged, dataChanged); ProfilerShort.End(); }
public void SpawnFlora(Vector3D pos) { if (m_planetEnvironmentSectors == null) { m_planetEnvironmentSectors = new Dictionary <Vector3I, MyPlanetEnvironmentSector>(500); } Vector3D gravity = GetWorldGravityNormalized(ref pos); Vector3D perpedincular = MyUtils.GetRandomPerpendicularVector(ref gravity); Vector3D third = Vector3D.Cross(gravity, perpedincular); perpedincular += third; Vector3I min = new Vector3I(-ENVIROMENT_EXTEND); Vector3I max = new Vector3I(ENVIROMENT_EXTEND); Vector3 offset = new Vector3(-MyPlanetEnvironmentSector.SECTOR_SIZE_METERS); for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.MoveNext()) { Vector3D currentPos = pos + it.Current * offset * perpedincular; currentPos = PlaceToOrbit(currentPos, ref gravity); if (false == ChekPosition(currentPos)) { Vector3I newSector = Vector3I.Floor(currentPos / MyPlanetEnvironmentSector.SECTOR_SIZE_METERS); if (m_planetSectorsPool == null) { m_planetSectorsPool = new MyDynamicObjectPool <MyPlanetEnvironmentSector>(400); } MyPlanetEnvironmentSector sector = m_planetSectorsPool.Allocate(); sector.Init(ref newSector, this); m_planetEnvironmentSectors[newSector] = sector; sector.PlaceItems(); } } Vector3I sectorCoords = Vector3I.Floor(PlaceToOrbit(pos, ref gravity) / MyPlanetEnvironmentSector.SECTOR_SIZE_METERS); Vector3I keepMin = sectorCoords + new Vector3I(-ENVIROMENT_EXTEND_KEEP); Vector3I keepMax = sectorCoords + new Vector3I(ENVIROMENT_EXTEND_KEEP); foreach (var enviromentSector in m_planetEnvironmentSectors) { if (enviromentSector.Key.IsInsideInclusive(keepMin, keepMax)) { m_sectorsToKeep.Add(enviromentSector.Key); } } }
public static ulong CutOutShape(MyVoxelBase voxelMap, MyShape shape) { Vector3I minCorner, maxCorner, numCells; GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells); ulong changedVolumeAmount = 0; for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext()) { Vector3I cellMinCorner, cellMaxCorner; GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner); var cacheMin = cellMinCorner - 1; var cacheMax = cellMaxCorner + 1; voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); ulong removedSum = 0; m_cache.Resize(cacheMin, cacheMax); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, 0, ref cacheMin, ref cacheMax); for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cacheMin; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove { continue; } Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); var volume = shape.GetVolume(ref vpos); if (volume == 0f) // if there is no intersection { continue; } var toRemove = (int)(MyVoxelConstants.VOXEL_CONTENT_FULL - (volume * MyVoxelConstants.VOXEL_CONTENT_FULL)); var newVal = Math.Min(toRemove, original); ulong removed = (ulong)Math.Abs(original - newVal); m_cache.Content(ref relPos, (byte)newVal); removedSum += removed; } if (removedSum > 0) { RemoveSmallVoxelsUsingChachedVoxels(); // must stay because of the around when filling voxels voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax); } changedVolumeAmount += removedSum; } return(changedVolumeAmount); }
public static ulong FillInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx) { Vector3I minCorner, maxCorner, numCells; ulong retValue = 0; GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells); for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext()) { Vector3I cellMinCorner, cellMaxCorner; GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner); Vector3I originalMinCorner = cellMinCorner; Vector3I originalMaxCorner = cellMaxCorner; voxelMap.Storage.ClampVoxelCoord(ref cellMinCorner, VOXEL_CLAMP_BORDER_DISTANCE); voxelMap.Storage.ClampVoxelCoord(ref cellMaxCorner, VOXEL_CLAMP_BORDER_DISTANCE); ClampingInfo minCornerClamping = CheckForClamping(originalMinCorner, cellMinCorner); ClampingInfo maxCornerClamping = CheckForClamping(originalMaxCorner, cellMaxCorner); m_cache.Resize(cellMinCorner, cellMaxCorner); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cellMinCorner, ref cellMaxCorner); ulong filledSum = 0; for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cellMinCorner; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_FULL) // if there is nothing to add { continue; } //if there was some claping, fill the clamp region with material if ((it.Current.X == cellMinCorner.X && minCornerClamping.X) || (it.Current.X == cellMaxCorner.X && maxCornerClamping.X) || (it.Current.Y == cellMinCorner.Y && minCornerClamping.Y) || (it.Current.Y == cellMaxCorner.Y && maxCornerClamping.Y) || (it.Current.Z == cellMinCorner.Z && minCornerClamping.Z) || (it.Current.Z == cellMaxCorner.Z && maxCornerClamping.Z)) { m_cache.Material(ref relPos, materialIdx); continue; } Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); var volume = shape.GetVolume(ref vpos); if (volume <= 0f) // there is nothing to fill { continue; } m_cache.Material(ref relPos, materialIdx); // set material var toFill = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); long newVal = MathHelper.Clamp(original + toFill, 0, Math.Max(original, toFill)); m_cache.Content(ref relPos, (byte)newVal); filledSum += (ulong)(newVal - original); } if (filledSum > 0) { RemoveSmallVoxelsUsingChachedVoxels(); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, ref cellMinCorner, ref cellMaxCorner); } retValue += filledSum; } return(retValue); }
private void EnsureMorphTargetExists(MyPrecalcJobRender.Args args, MyIsoMesh highResMesh) { // Ensure as many (ideally all) vertices have some mapping prepared. // This is here to resolve any missing parent only once for each vertex (main loop can visit vertices for each triangle they appear in). //var geometryData = highResMesh; for (int i = 0; i < highResMesh.VerticesCount; ++i) { Vector3 highResPosition = highResMesh.Positions[i]; Vertex lowResVertex; Vector3I vertexCell = highResMesh.Cells[i] >> 1; if (!m_morphMap.TryGetValue(vertexCell, out lowResVertex)) { float scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << args.Cell.Lod); Vector3 cell = highResPosition / scale; cell *= 0.5f; scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << (args.Cell.Lod + 1)); Vector3 lowResPosition = cell * scale; var cellMin = vertexCell; var cellMax = vertexCell + 1; // usually I need to find parent in this direction float nearestDist = float.PositiveInfinity; int nearestDistManhat = int.MaxValue; Vector3I?nearestCell = null; for (var it = new Vector3I.RangeIterator(ref cellMin, ref cellMax); it.IsValid(); it.MoveNext()) { Vertex morph; if (m_morphMap.TryGetValue(it.Current, out morph)) { var tmp = it.Current - cellMin; int distManhat = tmp.X + tmp.Y + tmp.Z; float dist = (morph.Target.Position - lowResPosition).LengthSquared(); if (distManhat < nearestDistManhat || (distManhat == nearestDistManhat && dist < nearestDist)) { nearestDist = dist; nearestDistManhat = distManhat; nearestCell = it.Current; } } } if (nearestCell.HasValue) { m_morphMap.Add(vertexCell, m_morphMap[nearestCell.Value]); } else { //Debug.Fail("I'm screwed"); } } } }
public void ReadRange(MyStorageData target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax, ref MyVoxelRequestFlags requestFlags) { ProfilerShort.Begin(GetType().Name + ".ReadRange"); try { const int SUBRANGE_SIZE_SHIFT = 3; const int SUBRANGE_SIZE = 1 << SUBRANGE_SIZE_SHIFT; var threshold = new Vector3I(SUBRANGE_SIZE); var rangeSize = lodVoxelRangeMax - lodVoxelRangeMin + 1; if ((dataToRead & MyStorageDataTypeFlags.Content) != 0) { target.ClearContent(0); } if ((rangeSize.X <= threshold.X && rangeSize.Y <= threshold.Y && rangeSize.Z <= threshold.Z) || !MyFakes.ENABLE_SPLIT_VOXEL_READ_QUERIES) { using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); } } else { // These optimizations don't work when splitting the range. requestFlags &= ~(MyVoxelRequestFlags.OneMaterial | MyVoxelRequestFlags.ContentChecked); MyVoxelRequestFlags flags = requestFlags; // splitting to smaller ranges to make sure the lock is not held for too long, preventing write on update thread // subranges could be aligned to multiple of their size for possibly better performance var steps = (rangeSize - 1) >> SUBRANGE_SIZE_SHIFT; for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref steps); it.IsValid(); it.MoveNext()) { flags = requestFlags; var offset = it.Current << SUBRANGE_SIZE_SHIFT; var min = lodVoxelRangeMin + offset; var max = min + SUBRANGE_SIZE - 1; Vector3I.Min(ref max, ref lodVoxelRangeMax, out max); Debug.Assert(min.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); Debug.Assert(max.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref offset, dataToRead, lodIndex, ref min, ref max, ref flags); } } // If the storage is consistent this should be fine. requestFlags = flags; } } finally { ProfilerShort.End(); } }
public static void CutOutShapeWithProperties( MyVoxelBase voxelMap, MyShape shape, out float voxelsCountInPercent, out MyVoxelMaterialDefinition voxelMaterial, Dictionary <MyVoxelMaterialDefinition, int> exactCutOutMaterials = null, bool updateSync = false, bool onlyCheck = false) { if (MySession.Static.EnableVoxelDestruction == false) { voxelsCountInPercent = 0; voxelMaterial = null; return; } ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()"); int originalSum = 0; int removedSum = 0; // Some shapes just ignore transforms so we round the bbox conservativelly by converting it to sphere var bbox = shape.GetWorldBoundaries(); var center = bbox.Center; var radius = (center - bbox.Min).Length(); MatrixD mat = voxelMap.PositionComp.WorldMatrix; MatrixD inverse; //Vector3D translation = mat.Translation; //mat.Translation = Vector3D.Zero; // invert is used to bring voxel coordinates back to world. inverse = voxelMap.PositionComp.WorldMatrixInvScaled;//MatrixD.Invert(ref mat, out inverse); Vector3 offset = voxelMap.StorageMin + voxelMap.SizeInMetresHalf; Vector3D.Transform(ref center, ref inverse, out center); // The transform is centered, but the code expects voxel local coordinates. center += voxelMap.SizeInMetresHalf; bbox = new BoundingBoxD(center - radius, center + radius); Vector3I minCorner, maxCorner; ComputeShapeBounds(voxelMap, ref bbox, Vector3.Zero, voxelMap.Storage.Size, out minCorner, out maxCorner); var cacheMin = minCorner - 1; var cacheMax = maxCorner + 1; voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); m_cache.Resize(cacheMin, cacheMax); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cacheMin, ref cacheMax); { var shapeCenter = bbox.Center; Vector3I exactCenter; MyVoxelCoordSystems.WorldPositionToVoxelCoord(Vector3.Zero, ref shapeCenter, out exactCenter); exactCenter -= cacheMin; exactCenter = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1); voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter)); } ProfilerShort.Begin("Main loop"); for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cacheMin; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove { continue; } Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToLocalPosition(ref it.Current, out vpos); // center vpos -= offset; // transform back to world space. Vector3D.Transform(ref vpos, ref mat, out vpos); var volume = shape.GetVolume(ref vpos); if (volume == 0f) // if there is no intersection { continue; } var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); var voxelMat = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref relPos)); var toRemove = (int)(maxRemove * voxelMat.DamageRatio); var newVal = MathHelper.Clamp(original - toRemove, 0, original - maxRemove); var removed = Math.Abs(original - newVal); if (!onlyCheck) { m_cache.Content(ref relPos, (byte)newVal); } originalSum += original; removedSum += removed; if (exactCutOutMaterials != null) { int value = 0; exactCutOutMaterials.TryGetValue(voxelMat, out value); value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed); exactCutOutMaterials[voxelMat] = value; } } if (removedSum > 0 && updateSync && Sync.IsServer) { shape.SendDrillCutOutRequest(voxelMap); } ProfilerShort.BeginNextBlock("Write"); if (removedSum > 0 && !onlyCheck) { // Clear all small voxel that may have been created during explosion. They can be created even outside the range of // explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the // explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we // will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove // B voxels too. //!! TODO AR & MK : check if this is needed !! RemoveSmallVoxelsUsingChachedVoxels(); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax); } ProfilerShort.End(); voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f; if (removedSum > 0) { CheckNeighbourStaticGridsAfterVoxelChanged(MyVoxelBase.OperationType.Cut, voxelMap, shape); } ProfilerShort.End(); }
public void ReadRange(MyStorageDataCache target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax) { ProfilerShort.Begin(GetType().Name + ".ReadRange"); try { const int SUBRANGE_SIZE_SHIFT = 3; const int SUBRANGE_SIZE = 1 << SUBRANGE_SIZE_SHIFT; var threshold = new Vector3I(SUBRANGE_SIZE); var rangeSize = lodVoxelRangeMax - lodVoxelRangeMin + 1; if ((dataToRead & MyStorageDataTypeFlags.Content) != 0) { target.ClearContent(0); } if ((dataToRead & MyStorageDataTypeFlags.Material) != 0) { //target.ClearMaterials(m_defaultMaterial); } if (rangeSize.X <= threshold.X && rangeSize.Y <= threshold.Y && rangeSize.Z <= threshold.Z) { using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax); } } else { // splitting to smaller ranges to make sure the lock is not held for too long, preventing write on update thread // subranges could be aligned to multiple of their size for possibly better performance var steps = (rangeSize - 1) >> SUBRANGE_SIZE_SHIFT; for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref steps); it.IsValid(); it.MoveNext()) { var offset = it.Current << SUBRANGE_SIZE_SHIFT; var min = lodVoxelRangeMin + offset; var max = min + SUBRANGE_SIZE - 1; Vector3I.Min(ref max, ref lodVoxelRangeMax, out max); Debug.Assert(min.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); Debug.Assert(max.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref offset, dataToRead, lodIndex, ref min, ref max); } } } } finally { ProfilerShort.End(); } }
private void ProcessMorphTargetCollisions(MyPrecalcJobRender.Args args, float vertexCellSizeInParentLod) { // Process collisions. // Remove collided vertices from map and add them to the list of collisions. for (int i = 0; i < m_collisionList.Count; ++i) { var vertexA = m_collisionList[i]; Vertex vertexB; if (m_morphMap.TryGetValue(vertexA.Cell, out vertexB)) { m_morphMap.Remove(vertexA.Cell); m_collisionList.Add(vertexB); } } // Try find better position for each vertex involved in collision. // mk:TODO This would ideally be done wthout MyVoxelCoordSystems float vertexHalfExpand = 0.25f * vertexCellSizeInParentLod; for (int i = 0; i < m_collisionList.Count; ++i) { var vertex = m_collisionList[i]; var center = vertex.Target.Position; var min = center - vertexHalfExpand; var max = center + vertexHalfExpand; Vector3I minVertexCell, maxVertexCell; MyVoxelCoordSystems.LocalPositionToVertexCell(args.Cell.Lod + 1, ref min, out minVertexCell); MyVoxelCoordSystems.LocalPositionToVertexCell(args.Cell.Lod + 1, ref max, out maxVertexCell); if (minVertexCell == maxVertexCell) { m_morphMap[minVertexCell] = vertex; } else { for (var it = new Vector3I.RangeIterator(ref minVertexCell, ref maxVertexCell); it.IsValid(); it.MoveNext()) { if (!m_morphMap.ContainsKey(it.Current)) m_morphMap[it.Current] = vertex; } } } m_collisionList.Clear(); }
private void EnsureMorphTargetExists(MyPrecalcJobRender.Args args, MyIsoMesh highResMesh) { // Ensure as many (ideally all) vertices have some mapping prepared. // This is here to resolve any missing parent only once for each vertex (main loop can visit vertices for each triangle they appear in). //var geometryData = highResMesh; for (int i = 0; i < highResMesh.VerticesCount; ++i) { Vector3 highResPosition = highResMesh.Positions[i]; Vertex lowResVertex; Vector3I vertexCell = highResMesh.Cells[i] >> 1; if (!m_morphMap.TryGetValue(vertexCell, out lowResVertex)) { float scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << args.Cell.Lod); Vector3 cell = highResPosition / scale; cell *= 0.5f; scale = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << (args.Cell.Lod + 1)); Vector3 lowResPosition = cell * scale; var cellMin = vertexCell; var cellMax = vertexCell + 1; // usually I need to find parent in this direction float nearestDist = float.PositiveInfinity; int nearestDistManhat = int.MaxValue; Vector3I? nearestCell = null; for (var it = new Vector3I.RangeIterator(ref cellMin, ref cellMax); it.IsValid(); it.MoveNext()) { Vertex morph; if (m_morphMap.TryGetValue(it.Current, out morph)) { var tmp = it.Current - cellMin; int distManhat = tmp.X + tmp.Y + tmp.Z; float dist = (morph.Target.Position - lowResPosition).LengthSquared(); if (distManhat < nearestDistManhat || (distManhat == nearestDistManhat && dist < nearestDist)) { nearestDist = dist; nearestDistManhat = distManhat; nearestCell = it.Current; } } } if (nearestCell.HasValue) { m_morphMap.Add(vertexCell, m_morphMap[nearestCell.Value]); } else { //Debug.Fail("I'm screwed"); } } } }
private int GetDivideIndex(ref Vector3I renderCellCoord) { // TODO: Optimize int divideIndex = 0; if (m_lodDivisions > 1) { BoundingBoxD lodAabb = m_boundingBoxes.GetAabb(m_boundingBoxes.GetRoot()); Vector3I test = Vector3I.Round(lodAabb.Size / (double)MyVoxelCoordSystems.RenderCellSizeInMeters(m_lod)); //Vector3I lodSizeMinusOne = m_parentClipmap.LodSizeMinusOne(m_lod); //Vector3I lodSize = lodSizeMinusOne + Vector3I.One; Vector3I lodSize = test; Vector3I lodSizeMinusOne = test - 1; Vector3I lodDivision = Vector3I.One * (m_lodDivisions - 1); var cellIterator = new Vector3I.RangeIterator(ref Vector3I.Zero, ref lodDivision); for (; cellIterator.IsValid(); cellIterator.MoveNext()) { Vector3I currentDivision = cellIterator.Current; Vector3I min = currentDivision * lodSize / m_lodDivisions; Vector3I max = (currentDivision + Vector3I.One) * lodSize / m_lodDivisions; if (renderCellCoord.IsInsideInclusive(ref min, ref max)) break; } Debug.Assert(cellIterator.IsValid(), "Valid division index not found!"); Vector3I foundCell = cellIterator.Current; divideIndex = GetDivideIndexFromMergeCell(ref foundCell); } return divideIndex; }
public static void CutOutShapeWithProperties( MyVoxelBase voxelMap, MyShape shape, out float voxelsCountInPercent, out MyVoxelMaterialDefinition voxelMaterial, Dictionary <MyVoxelMaterialDefinition, int> exactCutOutMaterials = null, bool updateSync = false, bool onlyCheck = false) { ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()"); int originalSum = 0; int removedSum = 0; var bbox = shape.GetWorldBoundaries(); Vector3I minCorner, maxCorner; ComputeShapeBounds(ref bbox, voxelMap.PositionLeftBottomCorner, voxelMap.Storage.Size, out minCorner, out maxCorner); var cacheMin = minCorner - 1; var cacheMax = maxCorner + 1; voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); m_cache.Resize(cacheMin, cacheMax); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cacheMin, ref cacheMax); { var shapeCenter = bbox.Center; Vector3I exactCenter; MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref shapeCenter, out exactCenter); exactCenter -= cacheMin; exactCenter = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1); voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter)); } for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cacheMin; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove { continue; } Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); var volume = shape.GetVolume(ref vpos); if (volume == 0f) // if there is no intersection { continue; } var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); var voxelMat = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref relPos)); var toRemove = (int)(maxRemove * voxelMat.DamageRatio); var newVal = MathHelper.Clamp(original - toRemove, 0, maxRemove); var removed = Math.Abs(original - newVal); if (!onlyCheck) { m_cache.Content(ref relPos, (byte)newVal); } originalSum += original; removedSum += removed; if (exactCutOutMaterials != null) { int value = 0; exactCutOutMaterials.TryGetValue(voxelMat, out value); value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed); exactCutOutMaterials[voxelMat] = value; } } if (removedSum > 0 && !onlyCheck) { // Clear all small voxel that may have been created during explosion. They can be created even outside the range of // explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the // explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we // will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove // B voxels too. //!! TODO AR & MK : check if this is needed !! RemoveSmallVoxelsUsingChachedVoxels(); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax); } if (removedSum > 0 && updateSync && Sync.IsServer) { shape.SendDrillCutOutRequest(voxelMap.SyncObject); } voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f; ProfilerShort.End(); }
private void ProcessMorphTargetCollisions(MyPrecalcJobRender.Args args, float vertexCellSizeInParentLod) { // Process collisions. // Remove collided vertices from map and add them to the list of collisions. for (int i = 0; i < m_collisionList.Count; ++i) { var vertexA = m_collisionList[i]; Vertex vertexB; if (m_morphMap.TryGetValue(vertexA.Cell, out vertexB)) { m_morphMap.Remove(vertexA.Cell); m_collisionList.Add(vertexB); } } // Try find better position for each vertex involved in collision. // mk:TODO This would ideally be done wthout MyVoxelCoordSystems float vertexHalfExpand = 0.25f * vertexCellSizeInParentLod; for (int i = 0; i < m_collisionList.Count; ++i) { var vertex = m_collisionList[i]; var center = vertex.Target.Position; var min = center - vertexHalfExpand; var max = center + vertexHalfExpand; Vector3I minVertexCell, maxVertexCell; MyVoxelCoordSystems.LocalPositionToVertexCell(args.Cell.Lod + 1, ref min, out minVertexCell); MyVoxelCoordSystems.LocalPositionToVertexCell(args.Cell.Lod + 1, ref max, out maxVertexCell); if (minVertexCell == maxVertexCell) { m_morphMap[minVertexCell] = vertex; } else { for (var it = new Vector3I.RangeIterator(ref minVertexCell, ref maxVertexCell); it.IsValid(); it.MoveNext()) { if (!m_morphMap.ContainsKey(it.Current)) { m_morphMap[it.Current] = vertex; } } } } m_collisionList.Clear(); }
public static void PaintInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx) { Vector3I minCorner, maxCorner, numCells; GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells); for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext()) { Vector3I cellMinCorner, cellMaxCorner; GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner); m_cache.Resize(cellMinCorner, cellMaxCorner); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, 0, ref cellMinCorner, ref cellMaxCorner); for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cellMinCorner; Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); float volume = shape.GetVolume(ref vpos); if (volume > 0.5f) { m_cache.Material(ref relPos, materialIdx); // set material } } voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Material, ref cellMinCorner, ref cellMaxCorner); } }
public static void CutOutShapeWithProperties( MyVoxelBase voxelMap, MyShape shape, out float voxelsCountInPercent, out MyVoxelMaterialDefinition voxelMaterial, Dictionary<MyVoxelMaterialDefinition, int> exactCutOutMaterials = null, bool updateSync = false, bool onlyCheck = false) { ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()"); int originalSum = 0; int removedSum = 0; var bbox = shape.GetWorldBoundaries(); Vector3I minCorner, maxCorner; ComputeShapeBounds(ref bbox, voxelMap.PositionLeftBottomCorner, voxelMap.Storage.Size, out minCorner, out maxCorner); var cacheMin = minCorner - 1; var cacheMax = maxCorner + 1; voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); m_cache.Resize(cacheMin, cacheMax); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cacheMin, ref cacheMax); { var shapeCenter = bbox.Center; Vector3I exactCenter; MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref shapeCenter, out exactCenter); exactCenter -= cacheMin; exactCenter = Vector3I.Clamp(exactCenter, Vector3I.Zero, m_cache.Size3D - 1); voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref exactCenter)); } for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cacheMin; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove continue; Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); var volume = shape.GetVolume(ref vpos); if (volume == 0f) // if there is no intersection continue; var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); var voxelMat = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref relPos)); var toRemove = (int)(maxRemove * voxelMat.DamageRatio); var newVal = MathHelper.Clamp(original - toRemove, 0, maxRemove); var removed = Math.Abs(original - newVal); if (!onlyCheck) m_cache.Content(ref relPos, (byte)newVal); originalSum += original; removedSum += removed; if (exactCutOutMaterials != null) { int value = 0; exactCutOutMaterials.TryGetValue(voxelMat, out value); value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed); exactCutOutMaterials[voxelMat] = value; } } if (removedSum > 0 && !onlyCheck) { // Clear all small voxel that may have been created during explosion. They can be created even outside the range of // explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the // explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we // will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove // B voxels too. //!! TODO AR & MK : check if this is needed !! RemoveSmallVoxelsUsingChachedVoxels(); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax); } if (removedSum > 0 && updateSync && Sync.IsServer) { shape.SendDrillCutOutRequest(voxelMap.SyncObject); } voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f; ProfilerShort.End(); }
public void GenerateFloraGraphics(Vector3D pos) { Debug.Assert(m_planetEnvironmentSectors != null, "null environment sector"); if (m_planetEnvironmentSectors == null) { return; } Vector3D gravity = GetWorldGravityNormalized(ref pos); Vector3D perpedincular = MyUtils.GetRandomPerpendicularVector(ref gravity); Vector3D third = Vector3D.Cross(gravity, perpedincular); perpedincular += third; Vector3I min = new Vector3I(-ENVIROMENT_EXTEND); Vector3I max = new Vector3I(ENVIROMENT_EXTEND); Vector3 offset = new Vector3(-MyPlanetEnvironmentSector.SECTOR_SIZE_METERS); for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.MoveNext()) { Vector3D currentPos = pos + it.Current * offset * perpedincular; currentPos = PlaceToOrbit(currentPos, ref gravity); Vector3I newSector = Vector3I.Floor(currentPos / MyPlanetEnvironmentSector.SECTOR_SIZE_METERS); MyPlanetEnvironmentSector sector; if (true == m_planetEnvironmentSectors.TryGetValue(newSector, out sector) && sector.HasGraphics == false) { sector.UpdateSectorGraphics(); } } }
public static void PaintInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx) { Vector3I minCorner, maxCorner, numCells; GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells); for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext()) { Vector3I cellMinCorner, cellMaxCorner; GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner); m_cache.Resize(cellMinCorner, cellMaxCorner); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, 0, ref cellMinCorner, ref cellMaxCorner); for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cellMinCorner; Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); float volume = shape.GetVolume(ref vpos); if (volume > 0.5f) m_cache.Material(ref relPos, materialIdx); // set material } voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Material, ref cellMinCorner, ref cellMaxCorner); } }
public void ReadRange(MyStorageDataCache target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax) { ProfilerShort.Begin(GetType().Name + ".ReadRange"); try { const int SUBRANGE_SIZE_SHIFT = 3; const int SUBRANGE_SIZE = 1 << SUBRANGE_SIZE_SHIFT; var threshold = new Vector3I(SUBRANGE_SIZE); var rangeSize = lodVoxelRangeMax - lodVoxelRangeMin + 1; if ((dataToRead & MyStorageDataTypeFlags.Content) != 0) { target.ClearContent(0); } if ((dataToRead & MyStorageDataTypeFlags.Material) != 0) { target.ClearMaterials(m_defaultMaterial); } if (rangeSize.X <= threshold.X && rangeSize.Y <= threshold.Y && rangeSize.Z <= threshold.Z) { using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax); } } else { // splitting to smaller ranges to make sure the lock is not held for too long, preventing write on update thread // subranges could be aligned to multiple of their size for possibly better performance var steps = (rangeSize - 1) >> SUBRANGE_SIZE_SHIFT; for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref steps); it.IsValid(); it.MoveNext()) { var offset = it.Current << SUBRANGE_SIZE_SHIFT; var min = lodVoxelRangeMin + offset; var max = min + SUBRANGE_SIZE - 1; Vector3I.Min(ref max, ref lodVoxelRangeMax, out max); Debug.Assert(min.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); Debug.Assert(max.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref offset, dataToRead, lodIndex, ref min, ref max); } } } } finally { ProfilerShort.End(); } }
public void PrefetchShapeOnRay(ref LineD ray) { Vector3I minCorner, maxCorner; MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref ray.From, out minCorner); MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref ray.To, out maxCorner); minCorner /= PHYSICS_SECTOR_SIZE_METERS; maxCorner /= PHYSICS_SECTOR_SIZE_METERS; for (var it = new Vector3I.RangeIterator(ref minCorner, ref maxCorner); it.IsValid(); it.MoveNext()) { if(m_physicsShapes.ContainsKey(it.Current)) { m_physicsShapes[it.Current].PrefetchShapeOnRay(ref ray); } } }
private void FindForestInitialCandidate() { BoundingBoxD groundBox = m_ground.PositionComp.WorldAABB; Vector3D boxSize = groundBox.Size; boxSize *= 0.1f; groundBox.Inflate(-boxSize); MyBBSetSampler sampler = new MyBBSetSampler(groundBox.Min, groundBox.Max); bool posIsValid = true; Vector3D worldPos = default(Vector3D); int counter = 0; do { // find random position for starting worldPos = sampler.Sample(); var worldPosProjected = worldPos; worldPosProjected.Y = 0.5f; posIsValid = true; counter++; Vector3D areaCheck = new Vector3D(20, 20, 20); foreach (var enqueued in m_initialForestLocations) { // only interested in XZ plane BoundingBoxD tmp = new BoundingBoxD(enqueued - areaCheck, enqueued + areaCheck); tmp.Min.Y = 0; tmp.Max.Y = 1; if (tmp.Contains(worldPosProjected) == ContainmentType.Contains) { posIsValid = false; break; } } } while (!posIsValid && counter != 10); if (!posIsValid) { // could not find any position return; } var lineStart = new Vector3D(worldPos.X, groundBox.Max.Y, worldPos.Z); var lineEnd = new Vector3D(worldPos.X, groundBox.Min.Y, worldPos.Z); LineD line = new LineD(lineStart, lineEnd); MyIntersectionResultLineTriangleEx? result = null; var correctGroundDefinition = MyDefinitionManager.Static.GetVoxelMaterialDefinition("Grass"); var materialId = correctGroundDefinition.Index; if (m_ground.GetIntersectionWithLine(ref line, out result, VRage.Components.IntersectionFlags.DIRECT_TRIANGLES)) { Vector3D intersectionPoint = result.Value.IntersectionPointInWorldSpace; Vector3I voxelCoord, minRead, maxRead; MyVoxelCoordSystems.WorldPositionToVoxelCoord(m_ground.PositionLeftBottomCorner, ref intersectionPoint, out voxelCoord); minRead = voxelCoord - Vector3I.One; maxRead = voxelCoord + Vector3I.One; m_ground.Storage.ReadRange(m_voxelCache, MyStorageDataTypeFlags.Material, 0, ref minRead, ref maxRead); var minLocal = Vector3I.Zero; var maxLocal = Vector3I.One * 2; var it = new Vector3I.RangeIterator(ref minLocal, ref maxLocal); while (it.IsValid()) { var vec = it.Current; var material = m_voxelCache.Material(ref vec); if (material == materialId) { // found a location var desired = voxelCoord - Vector3I.One + vec; Vector3D desiredWorldPosition = default(Vector3D); MyVoxelCoordSystems.VoxelCoordToWorldPosition(m_ground.PositionLeftBottomCorner, ref desired, out desiredWorldPosition); m_initialForestLocations.Enqueue(desiredWorldPosition); break; } it.MoveNext(); } } }
public void GenerateFloraGraphics(Vector3D pos) { Debug.Assert(m_planetEnvironmentSectors != null, "null environment sector"); if (m_planetEnvironmentSectors == null) { return; } Vector3D gravity = GetWorldGravityNormalized(ref pos); Vector3D perpedincular = MyUtils.GetRandomPerpendicularVector(ref gravity); Vector3D third = Vector3D.Cross(gravity, perpedincular); perpedincular += third; Vector3I min = new Vector3I(-ENVIROMENT_EXTEND); Vector3I max = new Vector3I(ENVIROMENT_EXTEND); Vector3 offset = new Vector3(-MyPlanetEnvironmentSector.SECTOR_SIZE_METERS); for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.MoveNext()) { Vector3D currentPos = pos + it.Current * offset * perpedincular; currentPos = PlaceToOrbit(currentPos, ref gravity); Vector3I newSector = Vector3I.Floor(currentPos / MyPlanetEnvironmentSector.SECTOR_SIZE_METERS); MyPlanetEnvironmentSector sector; if (true == m_planetEnvironmentSectors.TryGetValue(newSector, out sector) && sector.HasGraphics == false) { sector.UpdateSectorGraphics(); } } }
public static ulong FillInShape(MyVoxelBase voxelMap, MyShape shape, byte materialIdx) { Vector3I minCorner, maxCorner, numCells; ulong retValue = 0; GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells); for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext()) { Vector3I cellMinCorner, cellMaxCorner; GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner); Vector3I originalMinCorner = cellMinCorner; Vector3I originalMaxCorner = cellMaxCorner; voxelMap.Storage.ClampVoxelCoord(ref cellMinCorner, VOXEL_CLAMP_BORDER_DISTANCE); voxelMap.Storage.ClampVoxelCoord(ref cellMaxCorner, VOXEL_CLAMP_BORDER_DISTANCE); ClampingInfo minCornerClamping = CheckForClamping(originalMinCorner, cellMinCorner); ClampingInfo maxCornerClamping = CheckForClamping(originalMaxCorner, cellMaxCorner); m_cache.Resize(cellMinCorner, cellMaxCorner); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref cellMinCorner, ref cellMaxCorner); ulong filledSum = 0; for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cellMinCorner; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_FULL) // if there is nothing to add continue; //if there was some claping, fill the clamp region with material if ((it.Current.X == cellMinCorner.X && minCornerClamping.X) || (it.Current.X == cellMaxCorner.X && maxCornerClamping.X) || (it.Current.Y == cellMinCorner.Y && minCornerClamping.Y) || (it.Current.Y == cellMaxCorner.Y && maxCornerClamping.Y) || (it.Current.Z == cellMinCorner.Z && minCornerClamping.Z) || (it.Current.Z == cellMaxCorner.Z && maxCornerClamping.Z)) { m_cache.Material(ref relPos, materialIdx); continue; } Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); var volume = shape.GetVolume(ref vpos); if (volume <= 0f) // there is nothing to fill continue; m_cache.Material(ref relPos, materialIdx); // set material var toFill = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); long newVal = MathHelper.Clamp(original + toFill, 0, Math.Max(original, toFill)); m_cache.Content(ref relPos, (byte)newVal); filledSum += (ulong)(newVal - original); } if (filledSum > 0) { RemoveSmallVoxelsUsingChachedVoxels(); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, ref cellMinCorner, ref cellMaxCorner); } retValue += filledSum; } return retValue; }
public void SpawnFlora(Vector3D pos) { if (m_planetEnvironmentSectors == null) { m_planetEnvironmentSectors = new Dictionary<Vector3I, MyPlanetEnvironmentSector>(500); } Vector3D gravity = GetWorldGravityNormalized(ref pos); Vector3D perpedincular = MyUtils.GetRandomPerpendicularVector(ref gravity); Vector3D third = Vector3D.Cross(gravity, perpedincular); perpedincular += third; Vector3I min = new Vector3I(-ENVIROMENT_EXTEND); Vector3I max = new Vector3I(ENVIROMENT_EXTEND); Vector3 offset = new Vector3(-MyPlanetEnvironmentSector.SECTOR_SIZE_METERS); for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.MoveNext()) { Vector3D currentPos = pos + it.Current * offset * perpedincular; currentPos = PlaceToOrbit(currentPos, ref gravity); if (false == ChekPosition(currentPos)) { Vector3I newSector = Vector3I.Floor(currentPos / MyPlanetEnvironmentSector.SECTOR_SIZE_METERS); if (m_planetSectorsPool == null) { m_planetSectorsPool = new MyDynamicObjectPool<MyPlanetEnvironmentSector>(400); } MyPlanetEnvironmentSector sector = m_planetSectorsPool.Allocate(); sector.Init(ref newSector, this); m_planetEnvironmentSectors[newSector] = sector; sector.PlaceItems(); } } Vector3I sectorCoords = Vector3I.Floor(PlaceToOrbit(pos, ref gravity) / MyPlanetEnvironmentSector.SECTOR_SIZE_METERS); Vector3I keepMin = sectorCoords + new Vector3I(-ENVIROMENT_EXTEND_KEEP); Vector3I keepMax = sectorCoords + new Vector3I(ENVIROMENT_EXTEND_KEEP); foreach (var enviromentSector in m_planetEnvironmentSectors) { if (enviromentSector.Key.IsInsideInclusive(keepMin, keepMax)) { m_sectorsToKeep.Add(enviromentSector.Key); } } }
public static ulong CutOutShape(MyVoxelBase voxelMap, MyShape shape) { Vector3I minCorner, maxCorner, numCells; GetVoxelShapeDimensions(voxelMap, shape, out minCorner, out maxCorner, out numCells); ulong changedVolumeAmount = 0; for (var itCells = new Vector3I.RangeIterator(ref Vector3I.Zero, ref numCells); itCells.IsValid(); itCells.MoveNext()) { Vector3I cellMinCorner, cellMaxCorner; GetCellCorners(ref minCorner, ref maxCorner, ref itCells, out cellMinCorner, out cellMaxCorner); var cacheMin = cellMinCorner - 1; var cacheMax = cellMaxCorner + 1; voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); ulong removedSum = 0; m_cache.Resize(cacheMin, cacheMax); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, 0, ref cacheMin, ref cacheMax); for (var it = new Vector3I.RangeIterator(ref cellMinCorner, ref cellMaxCorner); it.IsValid(); it.MoveNext()) { var relPos = it.Current - cacheMin; // get original amount var original = m_cache.Content(ref relPos); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove continue; Vector3D vpos; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref it.Current, out vpos); var volume = shape.GetVolume(ref vpos); if (volume == 0f) // if there is no intersection continue; var toRemove = (int)(MyVoxelConstants.VOXEL_CONTENT_FULL - (volume * MyVoxelConstants.VOXEL_CONTENT_FULL)); var newVal = Math.Min(toRemove, original); ulong removed = (ulong)Math.Abs(original - newVal); m_cache.Content(ref relPos, (byte)newVal); removedSum += removed; } if (removedSum > 0) { RemoveSmallVoxelsUsingChachedVoxels(); // must stay because of the around when filling voxels voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.Content, ref cacheMin, ref cacheMax); } changedVolumeAmount += removedSum; } return changedVolumeAmount; }
public void ReadRange(MyStorageData target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax, ref MyVoxelRequestFlags requestFlags) { ProfilerShort.Begin(GetType().Name + ".ReadRange"); try { const int SUBRANGE_SIZE_SHIFT = 3; const int SUBRANGE_SIZE = 1 << SUBRANGE_SIZE_SHIFT; var threshold = new Vector3I(SUBRANGE_SIZE); var rangeSize = lodVoxelRangeMax - lodVoxelRangeMin + 1; if ((dataToRead & MyStorageDataTypeFlags.Content) != 0) { target.ClearContent(0); } if ((rangeSize.X <= threshold.X && rangeSize.Y <= threshold.Y && rangeSize.Z <= threshold.Z) || !MyFakes.ENABLE_SPLIT_VOXEL_READ_QUERIES) { using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); } } else { // These optimizations don't work when splitting the range. requestFlags &= ~(MyVoxelRequestFlags.OneMaterial | MyVoxelRequestFlags.ContentChecked); MyVoxelRequestFlags flags = requestFlags; // splitting to smaller ranges to make sure the lock is not held for too long, preventing write on update thread // subranges could be aligned to multiple of their size for possibly better performance var steps = (rangeSize - 1) >> SUBRANGE_SIZE_SHIFT; for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref steps); it.IsValid(); it.MoveNext()) { flags = requestFlags; var offset = it.Current << SUBRANGE_SIZE_SHIFT; var min = lodVoxelRangeMin + offset; var max = min + SUBRANGE_SIZE - 1; Vector3I.Min(ref max, ref lodVoxelRangeMax, out max); Debug.Assert(min.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); Debug.Assert(max.IsInsideInclusive(ref lodVoxelRangeMin, ref lodVoxelRangeMax)); using (m_lock.AcquireSharedUsing()) { ReadRangeInternal(target, ref offset, dataToRead, lodIndex, ref min, ref max, ref flags); } } // If the storage is consistent this should be fine. requestFlags = flags; } } finally { ProfilerShort.End(); } }