internal void ReadContentRange(MyStorageData target, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { float lodVoxelSizeHalf; BoundingBox queryBox; BoundingSphere querySphere; SetupReading(lodIndex, ref minInLod, ref maxInLod, out lodVoxelSizeHalf, out queryBox, out querySphere); float lodVoxelSize = 2f * lodVoxelSizeHalf; ProfilerShort.Begin("Testing removed shapes"); var overlappedRemovedShapes = OverlappedRemovedShapes; overlappedRemovedShapes.Clear(); ContainmentType testRemove = ContainmentType.Disjoint; for (int i = 0; i < m_data.RemovedShapes.Length; ++i) { var test = m_data.RemovedShapes[i].Contains(ref queryBox, ref querySphere, lodVoxelSize); if (test == ContainmentType.Contains) { testRemove = ContainmentType.Contains; break; // completely empty so we can leave } else if (test == ContainmentType.Intersects) { testRemove = ContainmentType.Intersects; overlappedRemovedShapes.Add(m_data.RemovedShapes[i]); } } ProfilerShort.End(); if (testRemove == ContainmentType.Contains) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_EMPTY); ProfilerShort.End(); return; } ProfilerShort.Begin("Testing filled shapes"); var overlappedFilledShapes = OverlappedFilledShapes; overlappedFilledShapes.Clear(); ContainmentType testFill = ContainmentType.Disjoint; for (int i = 0; i < m_data.FilledShapes.Length; ++i) { var test = m_data.FilledShapes[i].Contains(ref queryBox, ref querySphere, lodVoxelSize); if (test == ContainmentType.Contains) { overlappedFilledShapes.Clear(); testFill = ContainmentType.Contains; break; } else if (test == ContainmentType.Intersects) { overlappedFilledShapes.Add(m_data.FilledShapes[i]); testFill = ContainmentType.Intersects; } } ProfilerShort.End(); if (testFill == ContainmentType.Disjoint) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_EMPTY); ProfilerShort.End(); return; } else if (testRemove == ContainmentType.Disjoint && testFill == ContainmentType.Contains) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_FULL); ProfilerShort.End(); return; } ProfilerShort.Begin("Distance field computation"); Vector3I v = minInLod; Vector3 localPos = v * lodVoxelSize; Vector3 localPosStart = v * lodVoxelSize; var writeOffsetLoc = writeOffset - minInLod; for (v.Z = minInLod.Z; v.Z <= maxInLod.Z; ++v.Z) { for (v.Y = minInLod.Y; v.Y <= maxInLod.Y; ++v.Y) { v.X = minInLod.X; var write2 = v + writeOffsetLoc; var write = target.ComputeLinear(ref write2); for (; v.X <= maxInLod.X; ++v.X) { //Vector3 localPos = v * lodVoxelSize; //ProfilerShort.Begin("Dist filled"); float distFill; if (testFill == ContainmentType.Contains) { distFill = -1f; } else { //ProfilerShort.Begin("shape distances"); distFill = 1f; foreach (var shape in overlappedFilledShapes) { distFill = Math.Min(distFill, shape.SignedDistance(ref localPos, lodVoxelSize, m_data.MacroModule, m_data.DetailModule)); if (distFill <= -1) { break; } } //ProfilerShort.End(); } //ProfilerShort.BeginNextBlock("Dist removed"); float distRemoved = 1f; if (testRemove != ContainmentType.Disjoint) { foreach (var shape in overlappedRemovedShapes) { distRemoved = Math.Min(distRemoved, shape.SignedDistance(ref localPos, lodVoxelSize, m_data.MacroModule, m_data.DetailModule)); if (distRemoved <= -1) { break; } } } //ProfilerShort.BeginNextBlock("content"); float signedDist = MathHelper.Max(distFill, -distRemoved); var fillRatio = MathHelper.Clamp(-signedDist, -1f, 1f) * 0.5f + 0.5f; byte content = (byte)(fillRatio * MyVoxelConstants.VOXEL_CONTENT_FULL); target.Content(write, content); Debug.Assert(Math.Abs((((float)content) / MyVoxelConstants.VOXEL_CONTENT_FULL) - fillRatio) <= 0.5f); //ProfilerShort.End(); write += target.StepLinear; localPos.X += lodVoxelSize; } localPos.Y += lodVoxelSize; localPos.X = localPosStart.X; } localPos.Z += lodVoxelSize; localPos.Y = localPosStart.Y; } ProfilerShort.End(); }
public override void Draw() { base.Draw(); if (MySession.Static == null) { return; } if (m_showVoxelProbe) { float halfSize = m_probeSize * .5f; float lodSize = 1 << m_probeLod; if (m_moveProbe) { m_probePosition = MySector.MainCamera.Position + MySector.MainCamera.ForwardVector * m_probeSize * 3; } BoundingBox bb; BoundingBoxD bbp; // Box used for drawing and finding the probe and drawing bb = new BoundingBox(m_probePosition - halfSize, m_probePosition + halfSize); bbp = (BoundingBoxD)bb; m_voxels.Clear(); MyGamePruningStructure.GetAllVoxelMapsInBox(ref bbp, m_voxels); MyVoxelBase map = null; double distance = double.PositiveInfinity; foreach (var vox in m_voxels) { var d = Vector3D.Distance(vox.WorldMatrix.Translation, m_probePosition); if (d < distance) { distance = d; map = vox; } } ContainmentType cont = ContainmentType.Disjoint; if (map != null) { map = map.RootVoxel; Vector3 localPos = Vector3.Transform(m_probePosition, map.PositionComp.WorldMatrixInvScaled); localPos += map.SizeInMetresHalf; // Create similar bounding box in storage space bb = new BoundingBox(localPos - halfSize, localPos + halfSize); m_probedVoxel = map; Section("Probing {1}: {0}", map.StorageName, map.GetType().Name); Text("Probe mode: {0}", m_mode); if (m_mode == ProbeMode.Intersect) { Text("Local Pos: {0}", localPos); Text("Probe Size: {0}", m_probeSize); cont = map.Storage.Intersect(ref bb, false); Text("Result: {0}", cont.ToString()); bbp = (BoundingBoxD)bb; } else { Vector3I min = Vector3I.Floor(bb.Min / lodSize + .5f); Vector3I max = min + ((int)m_probeSize >> m_probeLod) - 1; bbp = new BoundingBoxD(min << m_probeLod, (max + 1) << m_probeLod); bbp.Translate(new Vector3D(-.5)); Text("Probe Size: {0}({1})", (max - min).X + 1, m_probeSize); Text("Probe LOD: {0}", m_probeLod); var requestData = (MyStorageDataTypeEnum)(int)m_mode; MyVoxelRequestFlags flags = MyVoxelRequestFlags.ContentChecked; m_target.Resize(max - min + 1); m_target.Clear(MyStorageDataTypeEnum.Content, 0); m_target.Clear(MyStorageDataTypeEnum.Material, 0); map.Storage.ReadRange(m_target, (MyStorageDataTypeFlags)(1 << (int)requestData), m_probeLod, ref min, ref max, ref flags); if (requestData == MyStorageDataTypeEnum.Content) { if (flags.HasFlag(MyVoxelRequestFlags.EmptyContent)) { cont = ContainmentType.Disjoint; } else if (flags.HasFlag(MyVoxelRequestFlags.FullContent)) { cont = ContainmentType.Contains; } else { int val = m_target.ValueWhenAllEqual(requestData); if (val == -1) { cont = ContainmentType.Intersects; } else if (val >= MyVoxelConstants.VOXEL_ISO_LEVEL) { cont = ContainmentType.Contains; } else { cont = ContainmentType.Disjoint; } } DrawContentsInfo(m_target); } else { cont = ContainmentType.Disjoint; DrawMaterialsInfo(m_target); } Text(Color.Yellow, 1.5f, "Voxel Editing:"); Text("Value to set (Ctrl+Mousewheel): {0}", m_valueToSet); if (m_probeLod != 0) { Text(Color.Red, "Writing to storage is only possible when probe is set to LOD 0"); } else { Text("Use primary mouse button to set."); Text("Position/Extents: {0}/{1}", bbp.Min, bbp.Extents); if (MyInput.Static.IsLeftMousePressed()) { if (requestData == MyStorageDataTypeEnum.Content) { m_target.BlockFillContent(Vector3I.Zero, m_target.Size3D - Vector3I.One, m_valueToSet); } else { m_target.BlockFillMaterial(Vector3I.Zero, m_target.Size3D - Vector3I.One, m_valueToSet); } map.Storage.WriteRange(m_target, (MyStorageDataTypeFlags)(1 << (int)requestData), ref min, ref max); } } } } else { Section("No Voxel Found"); Text("Probe mode: {0}", m_mode); Text("Probe Size: {0}", m_probeSize); } Color c = ColorForContainment(cont); if (map != null) { bbp = bbp.Translate(-map.SizeInMetresHalf); MyOrientedBoundingBoxD oobb = new MyOrientedBoundingBoxD(bbp, map.WorldMatrix); MyRenderProxy.DebugDrawOBB(oobb, c, 0.5f, true, false); } else { MyRenderProxy.DebugDrawAABB(bbp, c, 0.5f, 1.0f, true); } } }
internal void ReadContentRange(MyStorageData target, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { float lodVoxelSizeHalf; BoundingBox queryBox; BoundingSphere querySphere; SetupReading(lodIndex, ref minInLod, ref maxInLod, out lodVoxelSizeHalf, out queryBox, out querySphere); float lodVoxelSize = 2f * lodVoxelSizeHalf; ProfilerShort.Begin("Testing removed shapes"); var overlappedRemovedShapes = OverlappedRemovedShapes; overlappedRemovedShapes.Clear(); ContainmentType testRemove = ContainmentType.Disjoint; for (int i = 0; i < m_data.RemovedShapes.Length; ++i) { var test = m_data.RemovedShapes[i].Contains(ref queryBox, ref querySphere, lodVoxelSize); if (test == ContainmentType.Contains) { testRemove = ContainmentType.Contains; break; // completely empty so we can leave } else if (test == ContainmentType.Intersects) { testRemove = ContainmentType.Intersects; overlappedRemovedShapes.Add(m_data.RemovedShapes[i]); } } ProfilerShort.End(); if (testRemove == ContainmentType.Contains) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_EMPTY); ProfilerShort.End(); return; } ProfilerShort.Begin("Testing filled shapes"); var overlappedFilledShapes = OverlappedFilledShapes; overlappedFilledShapes.Clear(); ContainmentType testFill = ContainmentType.Disjoint; for (int i = 0; i < m_data.FilledShapes.Length; ++i) { var test = m_data.FilledShapes[i].Contains(ref queryBox, ref querySphere, lodVoxelSize); if (test == ContainmentType.Contains) { overlappedFilledShapes.Clear(); testFill = ContainmentType.Contains; break; } else if (test == ContainmentType.Intersects) { overlappedFilledShapes.Add(m_data.FilledShapes[i]); testFill = ContainmentType.Intersects; } } ProfilerShort.End(); if (testFill == ContainmentType.Disjoint) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_EMPTY); ProfilerShort.End(); return; } else if (testRemove == ContainmentType.Disjoint && testFill == ContainmentType.Contains) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_FULL); ProfilerShort.End(); return; } ProfilerShort.Begin("Distance field computation"); Vector3I v = minInLod; Vector3 localPos = v * lodVoxelSize; Vector3 localPosStart = v * lodVoxelSize; var writeOffsetLoc = writeOffset - minInLod; for (v.Z = minInLod.Z; v.Z <= maxInLod.Z; ++v.Z) { for (v.Y = minInLod.Y; v.Y <= maxInLod.Y; ++v.Y) { v.X = minInLod.X; var write2 = v + writeOffsetLoc; var write = target.ComputeLinear(ref write2); for (; v.X <= maxInLod.X; ++v.X) { //Vector3 localPos = v * lodVoxelSize; //ProfilerShort.Begin("Dist filled"); float distFill; if (testFill == ContainmentType.Contains) { distFill = -1f; } else { //ProfilerShort.Begin("shape distances"); distFill = 1f; foreach (var shape in overlappedFilledShapes) { distFill = Math.Min(distFill, shape.SignedDistance(ref localPos, lodVoxelSize, m_data.MacroModule, m_data.DetailModule)); if (distFill <= -1) break; } //ProfilerShort.End(); } //ProfilerShort.BeginNextBlock("Dist removed"); float distRemoved = 1f; if (testRemove != ContainmentType.Disjoint) { foreach (var shape in overlappedRemovedShapes) { distRemoved = Math.Min(distRemoved, shape.SignedDistance(ref localPos, lodVoxelSize, m_data.MacroModule, m_data.DetailModule)); if (distRemoved <= -1) break; } } //ProfilerShort.BeginNextBlock("content"); float signedDist = MathHelper.Max(distFill, -distRemoved); var fillRatio = MathHelper.Clamp(-signedDist, -1f, 1f) * 0.5f + 0.5f; byte content = (byte)(fillRatio * MyVoxelConstants.VOXEL_CONTENT_FULL); target.Content(write, content); Debug.Assert(Math.Abs((((float)content) / MyVoxelConstants.VOXEL_CONTENT_FULL) - fillRatio) <= 0.5f); //ProfilerShort.End(); write += target.StepLinear; localPos.X += lodVoxelSize; } localPos.Y += lodVoxelSize; localPos.X = localPosStart.X; } localPos.Z += lodVoxelSize; localPos.Y = localPosStart.Y; } ProfilerShort.End(); }