internal void Init(MyVoxelMap voxelMap) { m_voxelMap = voxelMap; var size = m_voxelMap.Size; m_cellsCount.X = size.X >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; m_cellsCount.Y = size.Y >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; m_cellsCount.Z = size.Z >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; }
public void Init(MyMwcObjectBuilder_VoxelHand_Cylinder objectBuilder, MyVoxelMap parentVoxelMap) { base.Init(objectBuilder, parentVoxelMap); this.Radius1 = objectBuilder.Radius1; this.Radius2 = objectBuilder.Radius2; this.Length = objectBuilder.Length; UpdateLocalVolume(); }
protected virtual void Init(MyMwcObjectBuilder_VoxelHand_Shape objectBuilder, MyVoxelMap parentVoxelMap) { base.Init(null, objectBuilder, parentVoxelMap); ModeType = objectBuilder.VoxelHandModeType; Material = objectBuilder.VoxelHandMaterial; SetWorldMatrix(Matrix.CreateWorld(objectBuilder.PositionAndOrientation.Position, objectBuilder.PositionAndOrientation.Forward, objectBuilder.PositionAndOrientation.Up)); Visible = false; }
public MyCellStorage(string name, Vector3I size, MyVoxelMap voxelMap) : base(name) { base.VoxelMap = voxelMap; Size = size; m_sizeInMeters = Size * MyVoxelConstants.VOXEL_SIZE_IN_METRES; m_dataCellsCount = Size / MyVoxelConstants.DATA_CELL_SIZE_IN_VOXELS; m_oreDepositCellsCount = m_dataCellsCount; AllocateContents(); }
public void Init(MyMwcObjectBuilder_VoxelHand_Cuboid objectBuilder, MyVoxelMap parentVoxelMap) { base.Init(objectBuilder, parentVoxelMap); Width1 = objectBuilder.Width1; Depth1 = objectBuilder.Depth1; Width2 = objectBuilder.Width2; Depth2 = objectBuilder.Depth2; Length = objectBuilder.Length; UpdateLocalVolume(); }
internal MyVoxelPhysicsBody(MyVoxelMap voxelMap): base(voxelMap, RigidBodyFlag.RBF_STATIC) { m_voxelMap = voxelMap; var shape = GetHavokShape(); if (!shape.IsZero) { CreateFromCollisionObject(shape, -m_voxelMap.SizeInMetresHalf, m_voxelMap.WorldMatrix); } else { IsEmpty = true; } }
public void Init(MyMwcObjectBuilder_VoxelHand_Sphere objectBuilder, MyVoxelMap parentVoxelMap) { base.Init(objectBuilder, parentVoxelMap); this.Radius = objectBuilder.Radius; UpdateLocalVolume(); }
// When tube/head mounted into voxels and is harvesting void StartInVoxel(MyVoxelMap voxelMap) { // We found voxel so we stop here m_inVoxelMap = voxelMap; CurrentState = MyHarvestingDeviceEnum.InVoxel; StopTubeMovingCue(); StartGrindingCue(); m_lastTimeParticleAdded = null; m_parentMinerShip.Physics.Clear(); m_parentMinerShip.Physics.Immovable = true; MyMwcVector3Int tempVoxelCoord = voxelMap.GetVoxelCenterCoordinateFromMeters(ref m_headPositionTransformed); m_originalVoxelContent = voxelMap.GetVoxelContent(ref tempVoxelCoord); m_voxelMaterial = voxelMap.GetVoxelMaterial(ref tempVoxelCoord); m_harvestingParticleEffect = MyParticlesManager.CreateParticleEffect((int)MyParticleEffectsIDEnum.Harvester_Harvesting); m_harvestingParticleEffect.UserBirthMultiplier = 0.25f; m_harvestingParticleEffect.UserRadiusMultiplier = 1; m_harvestingParticleEffect.UserColorMultiplier = new Vector4(3, 3, 3, 3); Matrix dirMatrix = MyMath.MatrixFromDir(WorldMatrix.Forward); m_harvestingParticleEffect.WorldMatrix = Matrix.CreateWorld(m_headPositionTransformed, dirMatrix.Forward, dirMatrix.Up); // Empty voxels are problematic and can lead to "extremely fast harvesting". So here we do this // trick and its effect will be that even empty voxels will take few seconds to harvest. if (m_originalVoxelContent == 0) m_originalVoxelContent = 1; m_actualVoxelContent = (float)m_originalVoxelContent; m_harvestingSpeed = m_actualVoxelContent / TIME_TO_HARVEST_WHOLE_VOXEL_IN_UPDATE_TIMES; if (!MyVoxelMapOreMaterials.CanBeHarvested(m_voxelMaterial)) { HUD.MyHud.ShowIndestructableAsteroidNotification(); StartReturningBack(); } }
/// <summary> /// Processes an asteroid Voxel using function callbacks. /// This allows for muti-threading, and generating content via algorithims. /// </summary> /// <param name="voxelMap"></param> /// <param name="multiThread"></param> /// <param name="material"></param> /// <param name="func"></param> /// <param name="readWrite"></param> /// <returns></returns> public static void ProcessAsteroid(MyVoxelMap voxelMap, bool multiThread, string material, Action <MyVoxelBuilderArgs> func, bool readWrite = true) { long counterTotal = (long)voxelMap.Size.X * (long)voxelMap.Size.Y * (long)voxelMap.Size.Z; long counter = 0; decimal progress = 0; var timer = new Stopwatch(); Debug.Write(string.Format("Building Asteroid : {0:000},", progress)); Console.Write(string.Format("Building Asteroid : {0:000},", progress)); Exception threadException = null; timer.Start(); if (!multiThread) { #region single thread processing for (var x = 0; x < voxelMap.Size.X; x++) { for (var y = 0; y < voxelMap.Size.Y; y++) { for (var z = 0; z < voxelMap.Size.Z; z++) { var coords = new Vector3I(x, y, z); byte volume = 0xff; var cellMaterial = material; if (readWrite) { voxelMap.GetVoxelMaterialContent(ref coords, out cellMaterial, out volume); } var args = new MyVoxelBuilderArgs(voxelMap.Size, coords, cellMaterial, volume, 0xff); try { func(args); } catch (Exception ex) { threadException = ex; break; } if (args.Volume != MyVoxelConstants.VOXEL_CONTENT_FULL) { voxelMap.SetVoxelContent(args.Volume, ref coords); } if (material != args.Material) { voxelMap.SetVoxelMaterialAndIndestructibleContent(args.Material, args.Indestructible, ref coords); } counter++; var prog = Math.Floor(counter / (decimal)counterTotal * 100); if (prog != progress) { progress = prog; Debug.Write(string.Format("{0:000},", progress)); } } } } #endregion } else { #region multi thread processing // TODO: re-write the multi thread processing to be more stable. // But still try and max out the processors. long threadCounter = counterTotal / MyVoxelConstants.VOXEL_DATA_CELLS_IN_RENDER_CELL_SIZE / MyVoxelConstants.VOXEL_DATA_CELLS_IN_RENDER_CELL_SIZE / MyVoxelConstants.VOXEL_DATA_CELLS_IN_RENDER_CELL_SIZE; var baseCoords = new Vector3I(0, 0, 0); for (baseCoords.X = 0; baseCoords.X < voxelMap.Size.X; baseCoords.X += MyVoxelConstants.VOXEL_DATA_CELLS_IN_RENDER_CELL_SIZE) { for (baseCoords.Y = 0; baseCoords.Y < voxelMap.Size.Y; baseCoords.Y += MyVoxelConstants.VOXEL_DATA_CELLS_IN_RENDER_CELL_SIZE) { for (baseCoords.Z = 0; baseCoords.Z < voxelMap.Size.Z; baseCoords.Z += MyVoxelConstants.VOXEL_DATA_CELLS_IN_RENDER_CELL_SIZE) { var task = new Task(obj => { var bgw = (MyVoxelTaskWorker)obj; var coords = new Vector3I(0, 0, 0); for (coords.X = bgw.BaseCoords.X; coords.X < bgw.BaseCoords.X + MyVoxelConstants.VOXEL_DATA_CELLS_IN_RENDER_CELL_SIZE; coords.X++) { for (coords.Y = bgw.BaseCoords.Y; coords.Y < bgw.BaseCoords.Y + MyVoxelConstants.VOXEL_DATA_CELLS_IN_RENDER_CELL_SIZE; coords.Y++) { for (coords.Z = bgw.BaseCoords.Z; coords.Z < bgw.BaseCoords.Z + MyVoxelConstants.VOXEL_DATA_CELLS_IN_RENDER_CELL_SIZE; coords.Z++) { byte volume = 0xff; var cellMaterial = material; if (readWrite) { voxelMap.GetVoxelMaterialContent(ref coords, out cellMaterial, out volume); } var args = new MyVoxelBuilderArgs(voxelMap.Size, coords, cellMaterial, volume, 0xff); try { func(args); } catch (Exception ex) { threadException = ex; threadCounter = 0; break; } if (args.Volume != MyVoxelConstants.VOXEL_CONTENT_FULL) { voxelMap.SetVoxelContent(args.Volume, ref coords); } if (material != args.Material) { voxelMap.SetVoxelMaterialAndIndestructibleContent(args.Material, args.Indestructible, ref coords); } } } } lock (Locker) { counter += (long)MyVoxelConstants.VOXEL_DATA_CELLS_IN_RENDER_CELL_SIZE * MyVoxelConstants.VOXEL_DATA_CELLS_IN_RENDER_CELL_SIZE * MyVoxelConstants.VOXEL_DATA_CELLS_IN_RENDER_CELL_SIZE; var prog = Math.Floor(counter / (decimal)counterTotal * 100); if (prog != progress) { progress = prog; Debug.Write(string.Format("{0:000},", progress)); Console.Write(string.Format("{0:000},", progress)); GC.Collect(); } threadCounter--; } }, new MyVoxelTaskWorker(baseCoords)); task.Start(); } } } GC.Collect(); while (threadCounter > 0) { System.Windows.Forms.Application.DoEvents(); } System.Threading.Thread.Sleep(100); System.Windows.Forms.Application.DoEvents(); #endregion } timer.Stop(); if (threadException != null) { throw threadException; } voxelMap.UpdateContentBounds(); var count = voxelMap.SumVoxelCells(); Debug.WriteLine(" Done. | {0} | VoxCells {1:#,##0}", timer.Elapsed, count); Console.WriteLine(" Done. | {0} | VoxCells {1:#,##0}", timer.Elapsed, count); }
public void FillAsteroid(MyVoxelMap asteroid, IMyVoxelFillProperties fillProperties) { var properties = (AsteroidByteFillProperties)fillProperties; IList <byte> baseAssets; Dictionary <byte, long> materialVoxelCells; asteroid.CalculateMaterialCellAssets(out baseAssets, out materialVoxelCells); var distribution = new List <double> { Double.NaN }; var materialSelection = new List <byte> { SpaceEngineersCore.Resources.GetMaterialIndex(properties.MainMaterial.Value) }; if (properties.SecondPercent > 0) { distribution.Add((double)properties.SecondPercent / 100); materialSelection.Add(SpaceEngineersCore.Resources.GetMaterialIndex(properties.SecondMaterial.Value)); } if (properties.ThirdPercent > 0) { distribution.Add((double)properties.ThirdPercent / 100); materialSelection.Add(SpaceEngineersCore.Resources.GetMaterialIndex(properties.ThirdMaterial.Value)); } if (properties.FourthPercent > 0) { distribution.Add((double)properties.FourthPercent / 100); materialSelection.Add(SpaceEngineersCore.Resources.GetMaterialIndex(properties.FourthMaterial.Value)); } if (properties.FifthPercent > 0) { distribution.Add((double)properties.FifthPercent / 100); materialSelection.Add(SpaceEngineersCore.Resources.GetMaterialIndex(properties.FifthMaterial.Value)); } if (properties.SixthPercent > 0) { distribution.Add((double)properties.SixthPercent / 100); materialSelection.Add(SpaceEngineersCore.Resources.GetMaterialIndex(properties.SixthMaterial.Value)); } if (properties.SeventhPercent > 0) { distribution.Add((double)properties.SeventhPercent / 100); materialSelection.Add(SpaceEngineersCore.Resources.GetMaterialIndex(properties.SeventhMaterial.Value)); } var newDistributiuon = new List <byte>(); int count; for (var i = 1; i < distribution.Count(); i++) { count = (int)Math.Floor(distribution[i] * baseAssets.Count); // Round down. for (var j = 0; j < count; j++) { newDistributiuon.Add(materialSelection[i]); } } count = baseAssets.Count - newDistributiuon.Count; for (var j = 0; j < count; j++) { newDistributiuon.Add(materialSelection[0]); } newDistributiuon.Shuffle(); asteroid.SetMaterialAssets(newDistributiuon); //asteroid.ForceVoxelFaceMaterial(_dataModel.BaseMaterial.DisplayName); }
public void VoxelLoadSaveVx2V1() { SpaceEngineersCore.LoadDefinitions(); var materials = SpaceEngineersCore.Resources.GetMaterialList(); Assert.IsTrue(materials.Count > 0, "Materials should exist. Has the developer got Space Engineers installed?"); const string fileOriginal = @".\TestAssets\AsteroidV1Format.vx2"; const string fileNew = @".\TestOutput\AsteroidV1Format_save.vx2"; var voxelMap = new MyVoxelMap(); voxelMap.Load(fileOriginal, materials[0].Id.SubtypeId); IList <byte> materialAssets; Dictionary <byte, long> materialVoxelCells; voxelMap.CalculateMaterialCellAssets(out materialAssets, out materialVoxelCells); Assert.AreEqual(594485, materialAssets.Count, "Asset count should be equal."); var asset0 = materialAssets.Where(c => c == 0).ToList(); Assert.AreEqual(0, asset0.Count, "asset0 count should be equal."); var asset1 = materialAssets.Where(c => c == 1).ToList(); Assert.AreEqual(0, asset1.Count, "asset1 Asset count should be equal."); var asset2 = materialAssets.Where(c => c == 2).ToList(); Assert.AreEqual(0, asset2.Count, "asset2 Asset count should be equal."); var asset3 = materialAssets.Where(c => c == 3).ToList(); Assert.AreEqual(251145, asset3.Count, "asset3 Asset count should be equal."); var asset4 = materialAssets.Where(c => c == 4).ToList(); Assert.AreEqual(0, asset4.Count, "asset4 Asset count should be equal."); var asset5 = materialAssets.Where(c => c == 5).ToList(); Assert.AreEqual(0, asset5.Count, "asset5 Asset count should be equal."); var asset6 = materialAssets.Where(c => c == 6).ToList(); Assert.AreEqual(217283, asset6.Count, "asset6 Asset count should be equal."); var asset7 = materialAssets.Where(c => c == 7).ToList(); Assert.AreEqual(237, asset7.Count, "asset7 Asset count should be equal."); var asset8 = materialAssets.Where(c => c == 8).ToList(); Assert.AreEqual(9608, asset8.Count, "asset8 Asset count should be equal."); var asset9 = materialAssets.Where(c => c == 9).ToList(); Assert.AreEqual(40801, asset9.Count, "asset9 Asset count should be equal."); var asset10 = materialAssets.Where(c => c == 10).ToList(); Assert.AreEqual(152, asset10.Count, "asset10 Asset count should be equal."); var assetNameCount = voxelMap.CountAssets(materialAssets); Assert.IsTrue(assetNameCount.Count > 0, "Contains assets."); voxelMap.Save(fileNew); var lengthOriginal = new FileInfo(fileOriginal).Length; var lengthNew = new FileInfo(fileNew).Length; Assert.AreEqual(88299, lengthOriginal, "File size must match."); Assert.AreEqual(72296, lengthNew, "File size must match."); }
/// <summary> /// Adds the vertices from the physical body (rock) that is inside the given OBB /// </summary> /// <param name="voxelMap"></param> /// <param name="border"></param> /// <param name="originPosition"></param> /// <param name="obb"></param> /// <param name="bbList"></param> private void AddVoxelVertices(MyVoxelMap voxelMap, float border, Vector3D originPosition, MyOrientedBoundingBoxD obb, List <BoundingBoxD> bbList) { AddVoxelMesh(voxelMap, voxelMap.Storage, null, border, originPosition, obb, bbList); }
public static MyStorageBase Load(MyVoxelMap voxelMap, string name) { Debug.Assert(name != null, "Name shouldn't be null"); MyStorageBase result; //If there are some voxels from multiplayer, use them (because it appears that we changed to server from client) if (!MySession.Static.VoxelMaps.TryGetStorage(name, out result)) { if (Multiplayer.Sync.IsServer && (MyVoxelMaps.MultiplayerVoxelMaps == null || MyVoxelMaps.MultiplayerVoxelMaps.Count == 0)) { var filePath = Path.Combine(MySession.Static.CurrentPath, name + MyVoxelConstants.FILE_EXTENSION); result = LoadFromFile(voxelMap, filePath); } else { Debug.Assert(MyVoxelMaps.MultiplayerVoxelMaps != null); Debug.Assert(MyVoxelMaps.MultiplayerVoxelMaps.ContainsKey(name)); result = Load(voxelMap, MyVoxelMaps.MultiplayerVoxelMaps[name], name); } } return result; }
/// <summary> /// Processes an asteroid Voxel using function callbacks. /// This allows for muti-threading, and generating content via algorithims. /// </summary> public static void ProcessAsteroid(MyVoxelMap voxelMap, bool multiThread, byte materialIndex, Action <MyVoxelBuilderArgs> func, bool readWrite = true) { long counterTotal = (long)voxelMap.Size.X * voxelMap.Size.Y * voxelMap.Size.Z; long counter = 0; decimal progress = 0; var timer = new Stopwatch(); Debug.Write($"Building Asteroid : {progress:000},"); Console.Write($"Building Asteroid : {progress:000},"); Exception threadException = null; timer.Start(); if (!multiThread) { #region single thread processing Vector3I block; const int cellSize = 64; var cacheSize = Vector3I.Min(new Vector3I(cellSize), voxelMap.Storage.Size); var oldCache = new MyStorageData(); // read the asteroid in chunks of 64 to avoid the Arithmetic overflow issue. for (block.Z = 0; block.Z < voxelMap.Storage.Size.Z; block.Z += cellSize) { for (block.Y = 0; block.Y < voxelMap.Storage.Size.Y; block.Y += cellSize) { for (block.X = 0; block.X < voxelMap.Storage.Size.X; block.X += cellSize) { oldCache.Resize(cacheSize); // LOD0 is required to read if you intend to write back to the voxel storage. Vector3I maxRange = block + cacheSize - 1; voxelMap.Storage.ReadRange(oldCache, MyStorageDataTypeFlags.ContentAndMaterial, 0, block, maxRange); 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) { var coords = block + p; byte volume = 0x0; byte cellMaterial = materialIndex; if (readWrite) { volume = oldCache.Content(ref p); cellMaterial = oldCache.Material(ref p); } var args = new MyVoxelBuilderArgs(voxelMap.Size, coords, cellMaterial, volume); try { func(args); } catch (Exception ex) { threadException = ex; break; } if (args.Volume != volume) { oldCache.Set(MyStorageDataTypeEnum.Content, ref p, args.Volume); } if (args.MaterialIndex != cellMaterial) { oldCache.Set(MyStorageDataTypeEnum.Material, ref p, args.MaterialIndex); } counter++; var prog = Math.Floor(counter / (decimal)counterTotal * 100); if (prog != progress) { progress = prog; Debug.Write($"{progress:000},"); } } } } voxelMap.Storage.WriteRange(oldCache, MyStorageDataTypeFlags.ContentAndMaterial, block, maxRange); } } } #endregion } else { #region multi thread processing // TODO: re-write the multi thread processing to be more stable. // But still try and max out the processors. Vector3I block; const int cellSize = 64; var cacheSize = Vector3I.Min(new Vector3I(cellSize), voxelMap.Storage.Size); long threadCounter = counterTotal / cellSize / cellSize / cellSize; for (block.Z = 0; block.Z < voxelMap.Storage.Size.Z; block.Z += cellSize) { for (block.Y = 0; block.Y < voxelMap.Storage.Size.Y; block.Y += cellSize) { for (block.X = 0; block.X < voxelMap.Storage.Size.X; block.X += cellSize) { var oldCache = new MyStorageData(); oldCache.Resize(cacheSize); // LOD1 is not detailed enough for content information on asteroids. Vector3I maxRange = block + cacheSize - 1; voxelMap.Storage.ReadRange(oldCache, MyStorageDataTypeFlags.ContentAndMaterial, 0, block, maxRange); var task = new Task(obj => { var bgw = (MyVoxelTaskWorker)obj; 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) { var coords = bgw.BaseCoords + p; byte volume = 0x0; byte cellMaterial = materialIndex; if (readWrite) { // read the existing material and volume into the arguments before passing the to args for processing. volume = bgw.VoxelCache.Content(ref p); cellMaterial = bgw.VoxelCache.Material(ref p); } var args = new MyVoxelBuilderArgs(voxelMap.Size, coords, cellMaterial, volume); try { func(args); } catch (Exception ex) { threadException = ex; threadCounter = 0; break; } if (args.Volume != volume) { bgw.VoxelCache.Set(MyStorageDataTypeEnum.Content, ref p, args.Volume); } if (args.MaterialIndex != cellMaterial) { bgw.VoxelCache.Set(MyStorageDataTypeEnum.Material, ref p, args.MaterialIndex); } counter++; var prog = Math.Floor(counter / (decimal)counterTotal * 100); if (prog != progress) { progress = prog; Debug.Write($"{progress:000},"); } } } } lock (Locker) { var b = bgw.BaseCoords; Vector3I mr = bgw.BaseCoords + cacheSize - 1; voxelMap.Storage.WriteRange(bgw.VoxelCache, MyStorageDataTypeFlags.ContentAndMaterial, b, mr); counter += (long)cellSize * cellSize * cellSize; var prog = Math.Floor(counter / (decimal)counterTotal * 100); if (prog != progress) { progress = prog; Debug.Write($"{progress:000},"); Console.Write($"{progress:000},"); GC.Collect(); } threadCounter--; } }, new MyVoxelTaskWorker(block, oldCache)); task.Start(); } } } GC.Collect(); while (threadCounter > 0) { System.Windows.Forms.Application.DoEvents(); } System.Threading.Thread.Sleep(100); System.Windows.Forms.Application.DoEvents(); #endregion } timer.Stop(); if (threadException != null) { throw threadException; } voxelMap.RefreshAssets(); //voxelMap.UpdateContentBounds(); Debug.WriteLine($" Done. | {timer.Elapsed} | VoxCells {voxelMap.VoxCells:#,##0}"); Console.WriteLine($" Done. | {timer.Elapsed} | VoxCells {voxelMap.VoxCells:#,##0}"); }
// Precalculate voxel cell into cache (makes triangles and vertex buffer from voxels) public void Precalc(MyVoxelPrecalcTaskItem task) { Profiler.Begin("MyVoxelPrecalcTask.Precalc"); m_precalcType = task.Type; m_resultVerticesCounter = 0; m_resultTrianglesCounter = 0; m_edgeVertexCalcCounter++; m_voxelMap = task.VoxelMap; m_voxelStart = task.VoxelStart; int lodIdx = MyVoxelGeometry.GetLodIndex(m_precalcType); CalcPolygCubeSize(lodIdx); // Copy voxels into temp array //using (Stats.Timing.Measure("NewPrecalc.CopyVoxelContents", MyStatTypeEnum.Sum, clearRateMs: TIMEOUT)) Profiler.Begin("NewPrecalc.CopyVoxelContents"); bool isMixed = CopyVoxelContents() == MyVoxelRangeType.MIXED; Profiler.End(); //using (Stats.Timing.Measure("Precalc.Geometry generation", MyStatTypeEnum.Sum, clearRateMs: TIMEOUT)) Profiler.Begin("Precalc.Geometry generation"); { if (isMixed) { var cache = ThreadLocalCache; // Size of voxel or cell (in meters) and size of voxel map / voxel cells ComputeSizeAndOrigin(lodIdx); var start = Vector3I.One; var end = m_polygCubes - 1; Vector3I coord0 = start; for (var it = new Vector3I.RangeIterator(ref start, ref end); it.IsValid(); it.GetNext(out coord0)) { // We can get this voxel content right from cache (not using GetVoxelContent method), because after CopyVoxelContents these array must be filled. But only content, not material, normal, etc. int cubeIndex = 0; if (cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 1; } if (cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 2; } if (cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 4; } if (cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 8; } if (cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 16; } if (cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 32; } if (cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 64; } if (cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 128; } // Cube is entirely in/out of the surface if (MyMarchingCubesConstants.EdgeTable[cubeIndex] == 0) { continue; } // We can get this voxel content right from cache (not using GetVoxelContent method), because after CopyVoxelContents these array must be filled. But only content, not material, normal, etc. Vector3I tempVoxelCoord0 = ComputeTemporaryVoxelData(cache, ref coord0, cubeIndex); // Create the triangles CreateTriangles(ref coord0, cubeIndex, ref tempVoxelCoord0); } } } Profiler.End(); //using (Stats.Timing.Measure("Precalc.PrepareCache", MyStatTypeEnum.Sum, clearRateMs: TIMEOUT)) Profiler.Begin("Precalc.PrepareCache"); { // Cache the vertices and triangles and precalculate the octree task.Cache.PrepareCache(m_resultVertices, m_resultVerticesCounter, m_resultTriangles, m_resultTrianglesCounter, m_positionScale, m_originPosition, task.Type == MyLodTypeEnum.LOD0); } Profiler.End(); Profiler.End(); }
private bool ExtractStationIntersect(bool tightIntersection) { // Make a shortlist of station Entities in the bounding box of the asteroid. var asteroidWorldAABB = new BoundingBoxD(DataModel.ContentBounds.Min + DataModel.PositionAndOrientation.Value.Position, DataModel.ContentBounds.Max + DataModel.PositionAndOrientation.Value.Position); var stations = MainViewModel.GetIntersectingEntities(asteroidWorldAABB).Where(e => e.ClassType == ClassType.LargeStation).Cast <StructureCubeGridModel>().ToList(); if (stations.Count == 0) { return(false); } var modified = false; var sourceFile = DataModel.SourceVoxelFilepath ?? DataModel.VoxelFilepath; var asteroid = new MyVoxelMap(); asteroid.Load(sourceFile, SpaceEngineersCore.Resources.GetDefaultMaterialName(), true); var total = stations.Sum(s => s.CubeGrid.CubeBlocks.Count); MainViewModel.ResetProgress(0, total); // Search through station entities cubes for intersection with this voxel. foreach (var station in stations) { var quaternion = station.PositionAndOrientation.Value.ToQuaternion(); foreach (var cube in station.CubeGrid.CubeBlocks) { MainViewModel.IncrementProgress(); var definition = SpaceEngineersApi.GetCubeDefinition(cube.TypeId, station.CubeGrid.GridSizeEnum, cube.SubtypeName); var orientSize = definition.Size.Transform(cube.BlockOrientation).Abs(); var min = cube.Min.ToVector3() * station.CubeGrid.GridSizeEnum.ToLength(); var max = (cube.Min + orientSize) * station.CubeGrid.GridSizeEnum.ToLength(); var p1 = Vector3D.Transform(min, quaternion) + station.PositionAndOrientation.Value.Position - (station.CubeGrid.GridSizeEnum.ToLength() / 2); var p2 = Vector3D.Transform(max, quaternion) + station.PositionAndOrientation.Value.Position - (station.CubeGrid.GridSizeEnum.ToLength() / 2); var cubeWorldAABB = new BoundingBoxD(Vector3.Min(p1, p2), Vector3.Max(p1, p2)); // find worldAABB of block. if (asteroidWorldAABB.Intersects(cubeWorldAABB)) { var pointMin = new Vector3I(cubeWorldAABB.Min - DataModel.PositionAndOrientation.Value.Position); var pointMax = new Vector3I(cubeWorldAABB.Max - DataModel.PositionAndOrientation.Value.Position); Vector3I coords; for (coords.Z = pointMin.Z; coords.Z <= pointMax.Z; coords.Z++) { for (coords.Y = pointMin.Y; coords.Y <= pointMax.Y; coords.Y++) { for (coords.X = pointMin.X; coords.X <= pointMax.X; coords.X++) { if (coords.X >= 0 && coords.Y >= 0 && coords.Z >= 0 && coords.X < asteroid.Size.X && coords.Y < asteroid.Size.Y && coords.Z < asteroid.Size.Z) { asteroid.SetVoxelContent(0, ref coords); } } } } modified = true; } } } MainViewModel.ClearProgress(); if (modified) { var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension); asteroid.Save(tempfilename); // replaces the existing asteroid file, as it is still the same size and dimentions. DataModel.SourceVoxelFilepath = tempfilename; } return(modified); }
private static MyStorageBase Load(MyVoxelMap voxelMap, Stream stream, string name) { Profiler.Begin("MyStorageBase.Load"); try { string storageType = stream.ReadString(); int version = stream.Read7BitEncodedInt(); MyStorageBase storage = null; MyVoxelStorageAttribute attr; if (!m_attributesByName.TryGetValue(storageType, out attr)) { Debug.Fail(string.Format("Encountered unknown storage type in voxel file: {0}", storageType)); return null; } storage = Activator.CreateInstance(attr.StorageType, name) as MyStorageBase; storage.VoxelMap = voxelMap; storage.LoadInternal(version, stream); return storage; } finally { Profiler.End(); } }
private static MyStorageBase Load(MyVoxelMap voxelMap, byte[] memoryBuffer, string name) { MyStorageBase storage; using (var ms = new MemoryStream(memoryBuffer, false)) using (var gz = new GZipStream(ms, CompressionMode.Decompress)) { storage = Load(voxelMap, gz, name); } storage.m_compressedData = memoryBuffer; return storage; }
private void SubtractAsteroidVolumeFrom(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 coords; var asteroid = new MyVoxelMap(); asteroid.Load(filenamePrimary, SpaceEngineersCore.Resources.GetDefaultMaterialName(), true); for (coords.Z = (int)modelPrimary.ContentBounds.Min.Z; coords.Z <= modelPrimary.ContentBounds.Max.Z; coords.Z++) { for (coords.Y = (int)modelPrimary.ContentBounds.Min.Y; coords.Y <= modelPrimary.ContentBounds.Max.Y; coords.Y++) { for (coords.X = (int)modelPrimary.ContentBounds.Min.X; coords.X <= modelPrimary.ContentBounds.Max.X; coords.X++) { byte volume; string cellMaterial; asteroid.GetVoxelMaterialContent(ref coords, out cellMaterial, out volume); var newCoord = ((minPrimary - min) + ((Vector3D)coords - modelPrimary.ContentBounds.Min)).RoundToVector3I(); newAsteroid.SetVoxelContent(volume, ref newCoord); newAsteroid.SetVoxelMaterialAndIndestructibleContent(cellMaterial, 0xff, ref newCoord); } } } asteroid.Load(filenameSecondary, SpaceEngineersCore.Resources.GetDefaultMaterialName(), true); for (coords.Z = (int)modelSecondary.ContentBounds.Min.Z; coords.Z <= modelSecondary.ContentBounds.Max.Z; coords.Z++) { for (coords.Y = (int)modelSecondary.ContentBounds.Min.Y; coords.Y <= modelSecondary.ContentBounds.Max.Y; coords.Y++) { for (coords.X = (int)modelSecondary.ContentBounds.Min.X; coords.X <= modelSecondary.ContentBounds.Max.X; coords.X++) { var newCoord = ((minSecondary - min) + ((Vector3D)coords - modelSecondary.ContentBounds.Min)).RoundToVector3I(); if (Vector3I.BoxContains(Vector3I.Zero, modelPrimary.Size - 1, newCoord)) { byte volume; string cellMaterial; asteroid.GetVoxelMaterialContent(ref coords, out cellMaterial, out volume); if (volume > 0) { byte existingVolume; string existingCellMaterial; newAsteroid.GetVoxelMaterialContent(ref newCoord, out existingCellMaterial, out existingVolume); if (existingVolume - volume < 0) { volume = 0; } else { volume = (byte)(existingVolume - volume); } newAsteroid.SetVoxelContent(volume, ref newCoord); } } } } } }
public static void CreateExplosionDebris(ref BoundingSphere explosionSphere, MyGroupMask groupMask, MyEntity entity, MyVoxelMap voxelMap) { CreateExplosionDebris(ref explosionSphere, groupMask, entity, voxelMap, ref entity.GetModelLod0().BoundingBox); }
private bool BuildEntity() { var filenamepart = Path.GetFileNameWithoutExtension(Filename); var filename = MainViewModel.CreateUniqueVoxelStorageName(filenamepart + MyVoxelMap.V2FileExtension); double multiplier; if (IsMultipleScale) { multiplier = MultipleScale; } else { multiplier = MaxLengthScale / Math.Max(Math.Max(OriginalModelSize.Height, OriginalModelSize.Width), OriginalModelSize.Depth); } var scale = new ScaleTransform3D(multiplier, multiplier, multiplier); var rotateTransform = MeshHelper.TransformVector(new System.Windows.Media.Media3D.Vector3D(0, 0, 0), -RotateRoll, RotateYaw - 90, RotatePitch + 90); SourceFile = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension); var model = MeshHelper.Load(Filename, ignoreErrors: true); var meshes = new List <MyVoxelRayTracer.MyMeshModel>(); var geometeries = new List <MeshGeometry3D>(); foreach (var model3D in model.Children) { var gm = (GeometryModel3D)model3D; var geometry = gm.Geometry as MeshGeometry3D; if (geometry != null) { geometeries.Add(geometry); } } meshes.Add(new MyVoxelRayTracer.MyMeshModel(geometeries.ToArray(), InsideStockMaterial.MaterialIndex, InsideStockMaterial.MaterialIndex)); #region handle dialogs and process the conversion var doCancel = false; var progressModel = new ProgressCancelModel { Title = Res.WnProgressTitle, SubTitle = Res.WnProgressTitle, DialogText = Res.WnProgressTxtTimeRemain + " " + Res.WnProgressTxtTimeCalculating }; var progressVm = new ProgressCancelViewModel(this, progressModel); progressVm.CloseRequested += delegate(object sender, EventArgs e) { doCancel = true; }; var cancelFunc = (Func <bool>) delegate { return(doCancel); }; var completedAction = (Action) delegate { progressVm.Close(); }; MyVoxelMap voxelMap = null; var action = (Action) delegate { voxelMap = MyVoxelRayTracer.ReadModelAsteroidVolmetic(model, meshes, scale, rotateTransform, TraceType, TraceCount, TraceDirection, progressModel.ResetProgress, progressModel.IncrementProgress, cancelFunc, completedAction); }; if (RunInLowPrioity) { System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.Idle; } _dialogService.ShowDialog <WindowProgressCancel>(this, progressVm, action); if (RunInLowPrioity) { System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.Normal; } #endregion if (doCancel || voxelMap == null) { IsValidEntity = false; NewEntity = null; } else { voxelMap.ForceShellMaterial(OutsideStockMaterial.Value, (byte)OutsideMaterialDepth); voxelMap.Save(SourceFile); var position = VRageMath.Vector3D.Zero; var forward = Vector3.Forward; var up = Vector3.Up; if (IsAbsolutePosition) { position = Position.ToVector3(); } else if (IsInfrontofPlayer) { // Figure out where the Character is facing, and plant the new construct centered in front of the Character, but "BuildDistance" units out in front. var lookVector = (VRageMath.Vector3D)_dataModel.CharacterPosition.Forward.ToVector3(); lookVector.Normalize(); BoundingBoxD content = voxelMap.BoundingContent.ToBoundingBoxD(); VRageMath.Vector3D?boundingIntersectPoint = content.IntersectsRayAt(content.Center, -lookVector * 5000d); if (!boundingIntersectPoint.HasValue) { boundingIntersectPoint = content.Center; } var distance = VRageMath.Vector3D.Distance(boundingIntersectPoint.Value, content.Center) + (float)BuildDistance; VRageMath.Vector3D vector = lookVector * distance; position = VRageMath.Vector3D.Add(_dataModel.CharacterPosition.Position, vector) - content.Center; } var entity = new MyObjectBuilder_VoxelMap(position, filename) { EntityId = SpaceEngineersApi.GenerateEntityId(IDType.ASTEROID), PersistentFlags = MyPersistentEntityFlags2.CastShadows | MyPersistentEntityFlags2.InScene, StorageName = Path.GetFileNameWithoutExtension(filename) }; entity.PositionAndOrientation = new MyPositionAndOrientation { Position = position, Forward = forward, Up = up }; IsValidEntity = voxelMap.BoundingContent.Size.Volume() > 0; NewEntity = entity; if (BeepWhenFinished) { System.Media.SystemSounds.Asterisk.Play(); } } return(!doCancel); }
public static void CreateExplosionDebris(ref BoundingSphere explosionSphere, MyGroupMask groupMask, MyEntity entity, MyVoxelMap voxelMap, ref BoundingBox bb) { // Number of debris is random, but not more than size of the offset array float scaleMul = explosionSphere.Radius / 4.0f; GeneratePositions(bb); foreach (Vector3 positionInLocalSpace in m_positions) { var positionInWorldSpace = Vector3.Transform(positionInLocalSpace, entity.WorldMatrix); MyExplosionDebrisModel newObj = m_objectPool.Allocate(true); if (newObj == null) { continue; } // Check if new object won't intersect any existing triangle - because if yes, then it will decrease JLX performace a lot float randomNewScale = MyMwcUtils.GetRandomFloat(scaleMul / 4, scaleMul); var sphere = new BoundingSphere(positionInWorldSpace, newObj.m_modelLod0.BoundingSphere.Radius * randomNewScale); MyEntity myEntitiesGetIntersectionWithSphere = MyEntities.GetIntersectionWithSphere(ref sphere); if ((myEntitiesGetIntersectionWithSphere == null || myEntitiesGetIntersectionWithSphere == entity) && (voxelMap == null || !voxelMap.DoOverlapSphereTest(sphere.Radius, sphere.Center))) { if (Vector3.DistanceSquared(positionInWorldSpace, explosionSphere.Center) > MyMwcMathConstants.EPSILON_SQUARED) { newObj.Start(positionInWorldSpace, randomNewScale, groupMask, true); newObj.Physics.LinearVelocity = GetDirection(positionInWorldSpace, explosionSphere.Center) * MyExplosionsConstants.EXPLOSION_DEBRIS_SPEED; MyEntities.Add(newObj); if (MyExplosion.DEBUG_EXPLOSIONS) { m_debugVoxelSpheres.Add(sphere); } } } else { // Put back to object pool newObj.Close(); } } }
public bool ExtractStationIntersect(IMainView mainViewModel, bool tightIntersection) { // Make a shortlist of station Entities in the bounding box of the asteroid. var asteroidWorldAABB = new BoundingBoxD((Vector3D)ContentBounds.Min + PositionAndOrientation.Value.Position, (Vector3D)ContentBounds.Max + PositionAndOrientation.Value.Position); var stations = mainViewModel.GetIntersectingEntities(asteroidWorldAABB).Where(e => e.ClassType == ClassType.LargeStation).Cast <StructureCubeGridModel>().ToList(); if (stations.Count == 0) { return(false); } var modified = false; var sourceFile = SourceVoxelFilepath ?? VoxelFilepath; var asteroid = new MyVoxelMap(); asteroid.Load(sourceFile); var total = stations.Sum(s => s.CubeGrid.CubeBlocks.Count); mainViewModel.ResetProgress(0, total); // Search through station entities cubes for intersection with this voxel. foreach (var station in stations) { var quaternion = station.PositionAndOrientation.Value.ToQuaternion(); foreach (var cube in station.CubeGrid.CubeBlocks) { mainViewModel.IncrementProgress(); var definition = SpaceEngineersApi.GetCubeDefinition(cube.TypeId, station.CubeGrid.GridSizeEnum, cube.SubtypeName); var orientSize = definition.Size.Transform(cube.BlockOrientation).Abs(); var min = cube.Min.ToVector3() * station.CubeGrid.GridSizeEnum.ToLength(); var max = (cube.Min + orientSize) * station.CubeGrid.GridSizeEnum.ToLength(); var p1 = Vector3D.Transform(min, quaternion) + station.PositionAndOrientation.Value.Position - (station.CubeGrid.GridSizeEnum.ToLength() / 2); var p2 = Vector3D.Transform(max, quaternion) + station.PositionAndOrientation.Value.Position - (station.CubeGrid.GridSizeEnum.ToLength() / 2); var cubeWorldAABB = new BoundingBoxD(Vector3.Min(p1, p2), Vector3.Max(p1, p2)); // find worldAABB of block. if (asteroidWorldAABB.Intersects(cubeWorldAABB)) { Vector3I block; var cacheSize = new Vector3I(64); Vector3D position = PositionAndOrientation.Value.Position; // read the asteroid in chunks of 64 to avoid the Arithmetic overflow issue. for (block.Z = 0; block.Z < asteroid.Storage.Size.Z; block.Z += 64) { for (block.Y = 0; block.Y < asteroid.Storage.Size.Y; block.Y += 64) { for (block.X = 0; block.X < asteroid.Storage.Size.X; block.X += 64) { var cache = new MyStorageData(); cache.Resize(cacheSize); // LOD1 is not detailed enough for content information on asteroids. Vector3I maxRange = block + cacheSize - 1; asteroid.Storage.ReadRange(cache, MyStorageDataTypeFlags.Content, 0, block, maxRange); bool changed = false; 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) { BoundingBoxD voxelCellBox = new BoundingBoxD(position + p + block, position + p + block + 1); ContainmentType contains = cubeWorldAABB.Contains(voxelCellBox); // TODO: finish tightIntersection. Will require high interpretation of voxel content volumes. if (contains == ContainmentType.Contains || contains == ContainmentType.Intersects) { cache.Content(ref p, 0); changed = true; } } } } if (changed) { asteroid.Storage.WriteRange(cache, MyStorageDataTypeFlags.Content, block, maxRange); modified = true; } } } } } } } mainViewModel.ClearProgress(); if (modified) { var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension); asteroid.Save(tempfilename); // replaces the existing asteroid file, as it is still the same size and dimentions. UpdateNewSource(asteroid, tempfilename); MaterialAssets = null; InitializeAsync(); } return(modified); }
/// <summary> /// Returns a position that should be safe to spawn at given the radius and position. /// </summary> /// <param name="collisionRadius">The radius of the object that is trying to spawn.</param> /// <param name="position">The position the object would like to spawn at.</param> /// <param name="forward">(Out) The forward vector the object should spawn with.</param> /// <param name="up">(Out) The up vector the object should spawn with.</param> /// <param name="planetSpawnHeightRatio">The ratio within the planet's max radius and atmosphere radius you are positioned in.</param> /// <param name="randomRangeMin">The minimum randomized distance that is added.</param> /// <param name="randomRangeMax">The minimum randomized distance that is added.</param> public static void GetSpawnPosition(float collisionRadius, ref Vector3D position, out Vector3D forward, out Vector3D up, float planetSpawnHeightRatio = 0.3f, float randomRangeMin = 500, float randomRangeMax = 650) { // Are we spawning near a planet? Vector3 gravity = MyGravityProviderSystem.CalculateNaturalGravityInPoint(position); if (gravity.LengthSquared() > 0) { MyPlanet planet = MyGravityProviderSystem.GetStrongestGravityWell(position); if (planet != null) { GetSpawnPositionNearPlanet(planet, collisionRadius, ref position, out forward, out up, planetSpawnHeightRatio, randomRangeMin, randomRangeMax); return; } } // Old logic, testing for asteroids and other objects double distance = 0; foreach (var entity in MyEntities.GetEntities()) { MyVoxelMap voxelMap = entity as MyVoxelMap; // Only test against voxels if (entity == null) { continue; } distance = MathHelper.Max(distance, entity.PositionComp.WorldVolume.Center.Length() + entity.PositionComp.WorldVolume.Radius); } // Random range from last voxel distance += MyUtils.GetRandomFloat(randomRangeMin, randomRangeMax); if (MyEntities.IsWorldLimited()) { distance = Math.Min(distance, MyEntities.WorldSafeHalfExtent()); } else { distance = Math.Min(distance, 20000); // limited spawn area in infinite worlds } // Compute random position forward = MyUtils.GetRandomVector3Normalized(); up = Vector3D.CalculatePerpendicularVector(forward); Vector3D randomizedPosition = position + (forward * distance); // Test if we can spawn here Vector3D?searchPosition = MyEntities.FindFreePlace(randomizedPosition, collisionRadius); if (searchPosition.HasValue) { randomizedPosition = searchPosition.Value; } // Make sure we didn't randomize into a planet gravity = MyGravityProviderSystem.CalculateNaturalGravityInPoint(randomizedPosition); if (gravity.LengthSquared() > 0) { MyPlanet planet = MyGravityProviderSystem.GetStrongestGravityWell(randomizedPosition); if (planet != null) { GetSpawnPositionNearPlanet(planet, collisionRadius, ref position, out forward, out up, planetSpawnHeightRatio, randomRangeMin, randomRangeMax); } else { position = randomizedPosition; } } else { position = randomizedPosition; } }
public void VoxelMaterialAssetsRandom() { SpaceEngineersCore.LoadDefinitions(); var materials = SpaceEngineersCore.Resources.GetMaterialList(); Assert.IsTrue(materials.Count > 0, "Materials should exist. Has the developer got Space Engineers installed?"); var stoneMaterial = materials.FirstOrDefault(m => m.Id.SubtypeId.Contains("Stone_05")); Assert.IsNotNull(stoneMaterial, "Stone material should exist."); var goldMaterial = materials.FirstOrDefault(m => m.Id.SubtypeId.Contains("Gold")); Assert.IsNotNull(goldMaterial, "Gold material should exist."); var uraniumMaterial = materials.FirstOrDefault(m => m.Id.SubtypeId.Contains("Uraninite_01")); Assert.IsNotNull(uraniumMaterial, "Uranium material should exist."); const string fileOriginal = @".\TestAssets\Arabian_Border_7.vx2"; const string fileNewVoxel = @".\TestOutput\Arabian_Border_7_mixed.vx2"; var voxelMap = new MyVoxelMap(); voxelMap.Load(fileOriginal, materials[0].Id.SubtypeId); IList <byte> materialAssets; Dictionary <byte, long> materialVoxelCells; voxelMap.CalculateMaterialCellAssets(out materialAssets, out materialVoxelCells); Assert.AreEqual(35465, materialAssets.Count, "Asset count should be equal."); var distribution = new[] { Double.NaN, .5, .25 }; var materialSelection = new[] { SpaceEngineersCore.Resources.GetMaterialIndex(stoneMaterial.Id.SubtypeId), SpaceEngineersCore.Resources.GetMaterialIndex(goldMaterial.Id.SubtypeId), SpaceEngineersCore.Resources.GetMaterialIndex(uraniumMaterial.Id.SubtypeId) }; var newDistributiuon = new List <byte>(); int count; for (var i = 1; i < distribution.Count(); i++) { count = (int)Math.Floor(distribution[i] * materialAssets.Count); // Round down. for (var j = 0; j < count; j++) { newDistributiuon.Add(materialSelection[i]); } } count = materialAssets.Count - newDistributiuon.Count; for (var j = 0; j < count; j++) { newDistributiuon.Add(materialSelection[0]); } newDistributiuon.Shuffle(); var assetNameCount = voxelMap.CountAssets(newDistributiuon); Assert.AreEqual(3, assetNameCount.Count, "Asset Mertials count should be equal."); Assert.AreEqual(8867, assetNameCount[stoneMaterial.Id.SubtypeId], "Asset Mertials count should be equal."); Assert.AreEqual(17732, assetNameCount[goldMaterial.Id.SubtypeId], "Asset Mertials count should be equal."); Assert.AreEqual(8866, assetNameCount[uraniumMaterial.Id.SubtypeId], "Asset Mertials count should be equal."); voxelMap.SetMaterialAssets(newDistributiuon); voxelMap.CalculateMaterialCellAssets(out materialAssets, out materialVoxelCells); var cellCount = voxelMap.SumVoxelCells(); voxelMap.Save(fileNewVoxel); }
public void FillAsteroid(MyVoxelMap asteroid, IMyVoxelFillProperties fillProperties) { var properties = (AsteroidSeedFillProperties)fillProperties; /* The full history behind this hack/crutch eludes me. * There are roids that won't change their materials unless their face materials forced to something other than current value. * So we have to do that manually by setting to a usually unused ore (uranium) and then reverting to the one we chose (=old one in case of a flaky roid) */ byte oldMaterial = asteroid.VoxelMaterial; asteroid.ForceVoxelFaceMaterial("Uraninite_01"); asteroid.ForceVoxelFaceMaterial(properties.MainMaterial.Value); // Cycle through veins info and add 'spherical' depisits to the voxel cell grid (not voxels themselves) int i; if (properties.FirstVeins > 0) { for (i = 0; i < properties.FirstVeins; i++) { asteroid.SeedMaterialSphere(properties.FirstMaterial.Value, (byte)properties.FirstRadius); } } if (properties.SecondVeins > 0) { for (i = 0; i < properties.SecondVeins; i++) { asteroid.SeedMaterialSphere(properties.SecondMaterial.Value, (byte)properties.SecondRadius); } } if (properties.ThirdVeins > 0) { for (i = 0; i < properties.ThirdVeins; i++) { asteroid.SeedMaterialSphere(properties.ThirdMaterial.Value, (byte)properties.ThirdRadius); } } if (properties.FourthVeins > 0) { for (i = 0; i < properties.FourthVeins; i++) { asteroid.SeedMaterialSphere(properties.FourthMaterial.Value, (byte)properties.FourthRadius); } } if (properties.FifthVeins > 0) { for (i = 0; i < properties.FifthVeins; i++) { asteroid.SeedMaterialSphere(properties.FifthMaterial.Value, (byte)properties.FifthRadius); } } if (properties.SixthVeins > 0) { for (i = 0; i < properties.SixthVeins; i++) { asteroid.SeedMaterialSphere(properties.SixthMaterial.Value, (byte)properties.SixthRadius); } } if (properties.SeventhVeins > 0) { for (i = 0; i < properties.SeventhVeins; i++) { asteroid.SeedMaterialSphere(properties.SeventhMaterial.Value, (byte)properties.SeventhRadius); } } // Hide the surface materials up to depth of 2 cells. asteroid.ForceShellMaterial(properties.MainMaterial.Value, 2); // This recovers material assigning ability for most roids (could be something specific to indestructibleContent property?) // And not for all, apparently :( //asteroid.ForceVoxelFaceMaterial(_dataModel.BaseMaterial.DisplayName); // don't change mattype // doesn't help //asteroid.ForceIndestructibleContent(0xff); // Alt ends }
// This method realy initiates/starts the missile // IMPORTANT: Direction vector must be normalized! public void Start(Vector3 position, Vector3 initialVelocity, Vector3 directionNormalized, MyMwcObjectBuilder_SmallShip_Ammo usedAmmo, MySmallShip minerShip) { m_usedAmmo = usedAmmo; m_ammoProperties = MyAmmoConstants.GetAmmoProperties(usedAmmo.AmmoType); m_gameplayProperties = MyGameplayConstants.GetGameplayProperties(m_usedAmmo, Faction); m_penetratedVoxelMap = null; m_wasPenetration = false; m_hasExplosion = false; m_isExploded = false; m_collidedEntity = null; m_collisionPoint = null; Matrix orientation = GetWorldRotation(); Vector3 pos = position; // Play missile thrust cue (looping) m_thrusterCue = MyAudio.AddCue3D(MySoundCuesEnum.WepMissileFly, pos, orientation.Forward, orientation.Up, this.Physics.LinearVelocity); m_light = MyLights.AddLight(); if (m_light != null) { m_light.Start(MyLight.LightTypeEnum.PointLight, GetPosition(), MyMissileHelperUtil.GetCannonShotLightColor(), 1, MyMissileConstants.MISSILE_LIGHT_RANGE); } m_diffuseColor = m_ammoProperties.TrailColor; switch (usedAmmo.AmmoType) { case MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_Basic: case MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_High_Speed: case MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_Armor_Piercing_Incendiary: case MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_SAPHEI: case MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_Proximity_Explosive: m_explosionType = MyExplosionTypeEnum.MISSILE_EXPLOSION; break; case MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_BioChem: m_explosionType = MyExplosionTypeEnum.BIOCHEM_EXPLOSION; break; case MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_EMP: m_explosionType = MyExplosionTypeEnum.EMP_EXPLOSION; break; case MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_Tunnel_Buster: m_explosionType = MyExplosionTypeEnum.BLASTER_EXPLOSION; break; default: throw new MyMwcExceptionApplicationShouldNotGetHere(); break; } this.Physics.Mass = m_gameplayProperties.WeightPerUnit; Vector3? correctedDirection = null; if (MyGameplayConstants.GameplayDifficultyProfile.EnableAimCorrection) { if (minerShip == MinerWars.AppCode.Game.Managers.Session.MySession.PlayerShip) { correctedDirection = MyEntities.GetDirectionFromStartPointToHitPointOfNearestObject(minerShip, position, m_ammoProperties.MaxTrajectory); } } if (correctedDirection != null) directionNormalized = correctedDirection.Value; base.Start(position, initialVelocity, directionNormalized, m_ammoProperties.DesiredSpeed, minerShip); if (correctedDirection != null) //override the base class behaviour, update the missile direction { Matrix ammoWorld = minerShip.WorldMatrix; ammoWorld.Translation = position; ammoWorld.Forward = correctedDirection.Value; SetWorldMatrix(ammoWorld); } m_smokeEffect = MyParticlesManager.CreateParticleEffect((int)MyParticleEffectsIDEnum.Smoke_CannonShot); m_smokeEffect.AutoDelete = false; m_smokeEffect.WorldMatrix = WorldMatrix; }
public MyNavigationPrimitive FindClosestPrimitive(Vector3D point, bool highLevel, ref double closestDistanceSq, MyVoxelMap voxelMap = null) { MyNavigationPrimitive retval = null; if (voxelMap != null) { MyVoxelNavigationMesh mesh = null; if (m_navigationMeshes.TryGetValue(voxelMap, out mesh)) { retval = mesh.FindClosestPrimitive(point, highLevel, ref closestDistanceSq); } } else { foreach (var entry in m_navigationMeshes) { MyNavigationPrimitive closest = entry.Value.FindClosestPrimitive(point, highLevel, ref closestDistanceSq); if (closest != null) { retval = closest; } } } return(retval); }
public MyObjectBuilder_EntityBase BuildEntity() { var asteroidCenter = new VRageMath.Vector3D(); var asteroidSize = new Vector3I(); string originalFile = null; if (IsStockVoxel) { var stockfile = StockVoxel.SourceFilename; if (StockMaterial == null || StockMaterial.Value == null) { SourceFile = stockfile; originalFile = SourceFile; var asteroid = new MyVoxelMap(); asteroid.Load(stockfile); asteroidCenter = asteroid.BoundingContent.Center; asteroidSize = asteroid.BoundingContent.SizeInt() + 1; // Content size } else { var asteroid = new MyVoxelMap(); asteroid.Load(stockfile); asteroid.ForceBaseMaterial(SpaceEngineersCore.Resources.GetDefaultMaterialName(), StockMaterial.Value); SourceFile = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension); asteroid.Save(SourceFile); originalFile = StockVoxel.SourceFilename; asteroidCenter = asteroid.BoundingContent.Center; asteroidSize = asteroid.BoundingContent.SizeInt() + 1; // Content size } } else if (IsFileVoxel) { originalFile = SourceFile; var asteroid = new MyVoxelMap(); asteroid.Load(SourceFile); asteroidCenter = asteroid.BoundingContent.Center; asteroidSize = asteroid.BoundingContent.SizeInt() + 1; // Content size if (StockMaterial != null && StockMaterial.Value != null) { asteroid.ForceBaseMaterial(SpaceEngineersCore.Resources.GetDefaultMaterialName(), StockMaterial.Value); SourceFile = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension); asteroid.Save(SourceFile); } } else if (IsSphere) { string material; if (StockMaterial != null && StockMaterial.Value != null) { material = StockMaterial.Value; } else { material = SpaceEngineersCore.Resources.GetDefaultMaterialName(); } originalFile = string.Format("sphere_{0}_{1}_{2}{3}", material.ToLowerInvariant(), SphereRadius, SphereShellRadius, MyVoxelMap.V2FileExtension); var asteroid = MyVoxelBuilder.BuildAsteroidSphere(SphereRadius > 32, SphereRadius, material, material, SphereShellRadius != 0, SphereShellRadius); // TODO: progress bar. asteroidCenter = asteroid.BoundingContent.Center; asteroidSize = asteroid.BoundingContent.SizeInt() + 1; // Content size SourceFile = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension); asteroid.Save(SourceFile); } // automatically number all files, and check for duplicate filenames. Filename = MainViewModel.CreateUniqueVoxelStorageName(originalFile); // Figure out where the Character is facing, and plant the new constrcut right in front. // Calculate the hypotenuse, as it will be the safest distance to place in front. double distance = Math.Sqrt(Math.Pow(asteroidSize.X, 2) + Math.Pow(asteroidSize.Y, 2) + Math.Pow(asteroidSize.Z, 2)) / 2; var vector = new BindableVector3DModel(_dataModel.CharacterPosition.Forward).Vector3D; vector.Normalize(); vector = System.Windows.Media.Media3D.Vector3D.Multiply(vector, distance); Position = new BindablePoint3DModel(Point3D.Add(new BindablePoint3DModel(_dataModel.CharacterPosition.Position).Point3D, vector)); //Forward = new BindableVector3DModel(_dataModel.CharacterPosition.Forward); //Up = new BindableVector3DModel(_dataModel.CharacterPosition.Up); Forward = new BindableVector3DModel(Vector3.Forward); // Asteroids currently don't have any orientation. Up = new BindableVector3DModel(Vector3.Up); var entity = new MyObjectBuilder_VoxelMap { EntityId = SpaceEngineersApi.GenerateEntityId(IDType.ASTEROID), PersistentFlags = MyPersistentEntityFlags2.CastShadows | MyPersistentEntityFlags2.InScene, StorageName = Path.GetFileNameWithoutExtension(Filename), PositionAndOrientation = new MyPositionAndOrientation { Position = Position.ToVector3D() - asteroidCenter, Forward = Forward.ToVector3(), Up = Up.ToVector3() } }; return(entity); }
private void RegisterVoxelMapEvents(MyVoxelMap voxelMap) { voxelMap.OnClose += voxelMap_OnClose; }
// Return reference to voxel map that intersects the box. If not voxel map found, null is returned. public static MyVoxelMap GetVoxelMapWhoseBoundingBoxIntersectsBox(ref BoundingBox boundingBox, MyVoxelMap ignoreVoxelMap) { for (int i = 0; i < m_voxelMaps.Count; i++) { MyVoxelMap voxelMap = m_voxelMaps[i]; if (voxelMap != ignoreVoxelMap) { if (voxelMap.IsBoxIntersectingBoundingBoxOfThisVoxelMap(ref boundingBox) == true) { return(voxelMap); } } } // If we get here, no intersection was found return(null); }
private static MyVoxelCacheCellRender LoadCell(MyVoxelMap voxelMap, ref Vector3I renderCellCoord, MyLodTypeEnum cellHashType) { Profiler.Begin("AddCell"); MyVoxelCacheCellRender ret = AddCell(voxelMap.VoxelMapId, ref renderCellCoord, cellHashType); ret.Begin(voxelMap, ref renderCellCoord); ret.CellHashType = cellHashType; Profiler.End(); if (cellHashType == MyLodTypeEnum.LOD0) { Profiler.Begin("LOD0 - queue cells"); m_dataCellsQueue.Clear(); // Create normal (LOD0) version for (int dataX = 0; dataX < MyVoxelConstants.RENDER_CELL_SIZE_IN_GEOMETRY_CELLS; dataX++) { for (int dataY = 0; dataY < MyVoxelConstants.RENDER_CELL_SIZE_IN_GEOMETRY_CELLS; dataY++) { for (int dataZ = 0; dataZ < MyVoxelConstants.RENDER_CELL_SIZE_IN_GEOMETRY_CELLS; dataZ++) { // Don't precalculate this cells now. Store it in queue and calculate all cells at once by MyVoxelPrecalc.PrecalcQueue() Vector3I dataCellCoord = new Vector3I( renderCellCoord.X * MyVoxelConstants.RENDER_CELL_SIZE_IN_GEOMETRY_CELLS + dataX, renderCellCoord.Y * MyVoxelConstants.RENDER_CELL_SIZE_IN_GEOMETRY_CELLS + dataY, renderCellCoord.Z * MyVoxelConstants.RENDER_CELL_SIZE_IN_GEOMETRY_CELLS + dataZ); MyVoxelGeometry.CellData cachedDataCell = voxelMap.Geometry.GetCellLater(MyLodTypeEnum.LOD0, ref dataCellCoord); if (cachedDataCell != null) { m_dataCellsQueue.Add(cachedDataCell); } } } } Profiler.BeginNextBlock("LOD0 - PrecalcQueue"); // Precalculate all queued data cells in parallel threads - using multiple cores if possible. MyVoxelPrecalc.PrecalcQueue(); Profiler.BeginNextBlock("LOD0 - AddTriangles"); ret.AddTriangles(m_dataCellsQueue); Profiler.End(); } else if (cellHashType == MyLodTypeEnum.LOD1) { Profiler.Begin("LOD1 - PrecalcImmediatelly"); m_helperLodCachedDataCell.Reset(); // Create LOD1 render cell MyVoxelPrecalc.PrecalcImmediatelly( new MyVoxelPrecalcTaskItem( MyLodTypeEnum.LOD1, voxelMap, m_helperLodCachedDataCell, new Vector3I( renderCellCoord.X * MyVoxelConstants.RENDER_CELL_SIZE_IN_GEOMETRY_CELLS, renderCellCoord.Y * MyVoxelConstants.RENDER_CELL_SIZE_IN_GEOMETRY_CELLS, renderCellCoord.Z * MyVoxelConstants.RENDER_CELL_SIZE_IN_GEOMETRY_CELLS))); Profiler.BeginNextBlock("LOD1 - AddTriangles"); m_dataCellsQueue.Clear(); m_dataCellsQueue.Add(m_helperLodCachedDataCell); ret.AddTriangles(m_dataCellsQueue); Profiler.End(); } else { throw new InvalidBranchException(); } ret.End(); return(ret); }
public void SaveCheckPointAndSandBox() { IsBusy = true; ActiveWorld.SaveCheckPointAndSector(true); // Manages the adding of new voxel files. foreach (var entity in Structures) { if (entity is StructureVoxelModel) { var voxel = (StructureVoxelModel)entity; if (voxel.SourceVoxelFilepath != null && File.Exists(voxel.SourceVoxelFilepath)) { // Any asteroid that already exists with same name, must be removed. if (File.Exists(voxel.VoxelFilepath)) { FileSystem.DeleteFile(voxel.VoxelFilepath, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin); } if (Path.GetExtension(voxel.SourceVoxelFilepath).Equals(MyVoxelMap.V1FileExtension, StringComparison.OrdinalIgnoreCase)) { // Convert between formats. var voxelmap = new MyVoxelMap(); voxelmap.Load(voxel.SourceVoxelFilepath, SpaceEngineersCore.Resources.GetDefaultMaterialName(), true); voxelmap.Save(voxel.VoxelFilepath); } else { File.Copy(voxel.SourceVoxelFilepath, voxel.VoxelFilepath); } voxel.SourceVoxelFilepath = null; } } if (entity is StructurePlanetModel) { var voxel = (StructurePlanetModel)entity; if (voxel.SourceVoxelFilepath != null && File.Exists(voxel.SourceVoxelFilepath)) { // Any asteroid that already exists with same name, must be removed. if (File.Exists(voxel.VoxelFilepath)) { FileSystem.DeleteFile(voxel.VoxelFilepath, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin); } File.Copy(voxel.SourceVoxelFilepath, voxel.VoxelFilepath); voxel.SourceVoxelFilepath = null; } } } // Manages the removal old voxels files. foreach (var file in SpaceEngineersCore.ManageDeleteVoxelList) { var filename = Path.Combine(ActiveWorld.Savepath, file); if (File.Exists(filename)) { FileSystem.DeleteFile(filename, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin); } } SpaceEngineersCore.ManageDeleteVoxelList.Clear(); IsModified = false; IsBusy = false; }
public MyObjectBuilder_EntityBase BuildEntity() { // Realign both asteroids to a common grid, so voxels can be lined up. Vector3I roundedPosLeft = SelectionLeft.WorldAABB.Min.RoundToVector3I(); Vector3D offsetPosLeft = SelectionLeft.WorldAABB.Min - (Vector3D)roundedPosLeft; // Use for everything. Vector3I roundedPosRight = (SelectionRight.WorldAABB.Min - offsetPosLeft).RoundToVector3I(); Vector3D offsetPosRight = SelectionRight.WorldAABB.Min - (Vector3D)roundedPosRight; // Use for everything. // calculate smallest allowable size for contents of both. const int paddCells = 3; // Force a calculation of the ContentBounds, as multi select in the ListView doesn't necessarily make it happen, or make it happen fast enough. SelectionLeft.LoadDetailsSync(); SelectionRight.LoadDetailsSync(); var minLeft = SelectionLeft.WorldAABB.Min + SelectionLeft.InflatedContentBounds.Min - offsetPosLeft; var minRight = SelectionRight.WorldAABB.Min + SelectionRight.InflatedContentBounds.Min - offsetPosRight; var min = Vector3D.Zero; var posOffset = Vector3D.Zero; var asteroidSize = Vector3I.Zero; switch (VoxelMergeType) { case VoxelMergeType.UnionVolumeLeftToRight: case VoxelMergeType.UnionVolumeRightToLeft: min = Vector3D.Min(minLeft, minRight) - paddCells; var max = Vector3D.Max(SelectionLeft.WorldAABB.Min + SelectionLeft.InflatedContentBounds.Max - offsetPosLeft, SelectionRight.WorldAABB.Min + SelectionRight.InflatedContentBounds.Max - offsetPosRight) + paddCells; posOffset = new Vector3D(minLeft.X < minRight.X ? offsetPosLeft.X : offsetPosRight.X, minLeft.Y < minRight.Y ? offsetPosLeft.Y : offsetPosRight.Y, minLeft.Z < minRight.Z ? offsetPosLeft.Z : offsetPosRight.Z); var size = (max - min).RoundToVector3I(); asteroidSize = MyVoxelBuilder.CalcRequiredSize(size); break; case VoxelMergeType.UnionMaterialLeftToRight: min = SelectionRight.WorldAABB.Min - offsetPosRight; posOffset = new Vector3D(minLeft.X < minRight.X ? offsetPosLeft.X : offsetPosRight.X, minLeft.Y < minRight.Y ? offsetPosLeft.Y : offsetPosRight.Y, minLeft.Z < minRight.Z ? offsetPosLeft.Z : offsetPosRight.Z); asteroidSize = SelectionRight.Size; break; case VoxelMergeType.UnionMaterialRightToLeft: min = SelectionLeft.WorldAABB.Min - offsetPosLeft; posOffset = new Vector3D(minLeft.X < minRight.X ? offsetPosLeft.X : offsetPosRight.X, minLeft.Y < minRight.Y ? offsetPosLeft.Y : offsetPosRight.Y, minLeft.Z < minRight.Z ? offsetPosLeft.Z : offsetPosRight.Z); asteroidSize = SelectionLeft.Size; break; case VoxelMergeType.SubtractVolumeLeftFromRight: min = SelectionRight.WorldAABB.Min - offsetPosRight; posOffset = new Vector3D(minLeft.X < minRight.X ? offsetPosLeft.X : offsetPosRight.X, minLeft.Y < minRight.Y ? offsetPosLeft.Y : offsetPosRight.Y, minLeft.Z < minRight.Z ? offsetPosLeft.Z : offsetPosRight.Z); asteroidSize = SelectionRight.Size; break; case VoxelMergeType.SubtractVolumeRightFromLeft: min = SelectionLeft.WorldAABB.Min - offsetPosLeft; posOffset = new Vector3D(minLeft.X < minRight.X ? offsetPosLeft.X : offsetPosRight.X, minLeft.Y < minRight.Y ? offsetPosLeft.Y : offsetPosRight.Y, minLeft.Z < minRight.Z ? offsetPosLeft.Z : offsetPosRight.Z); asteroidSize = SelectionLeft.Size; break; } // Prepare new asteroid. var newAsteroid = new MyVoxelMap(); newAsteroid.Create(asteroidSize, SpaceEngineersCore.Resources.GetDefaultMaterialIndex()); if (string.IsNullOrEmpty(MergeFileName)) { MergeFileName = "merge"; } var filename = MainViewModel.CreateUniqueVoxelStorageName(MergeFileName); // merge. switch (VoxelMergeType) { case VoxelMergeType.UnionVolumeLeftToRight: MergeAsteroidVolumeInto(ref newAsteroid, min, SelectionRight, SelectionLeft, minRight, minLeft); break; case VoxelMergeType.UnionVolumeRightToLeft: MergeAsteroidVolumeInto(ref newAsteroid, min, SelectionLeft, SelectionRight, minLeft, minRight); break; case VoxelMergeType.UnionMaterialLeftToRight: MergeAsteroidMaterialFrom(ref newAsteroid, min, SelectionRight, SelectionLeft, minRight, minLeft); break; case VoxelMergeType.UnionMaterialRightToLeft: MergeAsteroidMaterialFrom(ref newAsteroid, min, SelectionLeft, SelectionRight, minLeft, minRight); break; case VoxelMergeType.SubtractVolumeLeftFromRight: SubtractAsteroidVolumeFrom(ref newAsteroid, min, SelectionRight, SelectionLeft, minRight, minLeft); break; case VoxelMergeType.SubtractVolumeRightFromLeft: SubtractAsteroidVolumeFrom(ref newAsteroid, min, SelectionLeft, SelectionRight, minLeft, minRight); break; } // Generate Entity var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension); newAsteroid.Save(tempfilename); SourceFile = tempfilename; var position = min + posOffset; var entity = new MyObjectBuilder_VoxelMap(position, filename) { EntityId = SpaceEngineersApi.GenerateEntityId(IDType.ASTEROID), PersistentFlags = MyPersistentEntityFlags2.CastShadows | MyPersistentEntityFlags2.InScene, StorageName = Path.GetFileNameWithoutExtension(filename), PositionAndOrientation = new MyPositionAndOrientation { Position = position, Forward = Vector3.Forward, Up = Vector3.Up } }; return(entity); }
public void BuildEntities(out string[] sourceVoxelFiles, out MyObjectBuilder_EntityBase[] sourceEntities) { var entities = new List <MyObjectBuilder_EntityBase>(); var sourceFiles = new List <string>(); MainViewModel.ResetProgress(0, VoxelCollection.Count); foreach (var voxelDesign in VoxelCollection) { MainViewModel.Progress++; if (string.IsNullOrEmpty(voxelDesign.VoxelFile.SourceFilename) || !MyVoxelMap.IsVoxelMapFile(voxelDesign.VoxelFile.SourceFilename)) { continue; } var asteroid = new MyVoxelMap(); string tempSourcefilename = null; switch (AsteroidFillType) { case Support.AsteroidFillType.None: asteroid.Load(voxelDesign.VoxelFile.SourceFilename, voxelDesign.MainMaterial.Value, false); tempSourcefilename = voxelDesign.VoxelFile.SourceFilename; break; case AsteroidFillType.ByteFiller: asteroid.Load(voxelDesign.VoxelFile.SourceFilename, voxelDesign.MainMaterial.Value, false); var filler = new AsteroidByteFiller(); filler.FillAsteroid(asteroid, voxelDesign); tempSourcefilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension); asteroid.Save(tempSourcefilename); break; } // automatically number all files, and check for duplicate filenames. var filename = MainViewModel.CreateUniqueVoxelStorageName(voxelDesign.VoxelFile.Name + MyVoxelMap.V2FileExtension, entities.ToArray()); var radius = RandomUtil.GetDouble(MinimumRange, MaximumRange); var longitude = RandomUtil.GetDouble(0, 2 * Math.PI); var latitude = RandomUtil.GetDouble(-Math.PI / 2, (Math.PI / 2) + double.Epsilon); // Test data. Place asteroids items into a circle. //radius = 500; //longitude = Math.PI * 2 * ((double)voxelDesign.Index / VoxelCollection.Count); //latitude = 0; var x = radius * Math.Cos(latitude) * Math.Cos(longitude); var z = radius * Math.Cos(latitude) * Math.Sin(longitude); var y = radius * Math.Sin(latitude); var center = new Vector3D(CenterPositionX, CenterPositionY, CenterPositionZ); var position = center + new Vector3D(x, y, z) - asteroid.BoundingContent.Center; var entity = new MyObjectBuilder_VoxelMap(position, filename) { EntityId = SpaceEngineersApi.GenerateEntityId(IDType.ASTEROID), PersistentFlags = MyPersistentEntityFlags2.CastShadows | MyPersistentEntityFlags2.InScene, StorageName = Path.GetFileNameWithoutExtension(filename), PositionAndOrientation = new MyPositionAndOrientation { Position = position, Forward = Vector3.Forward, // Asteroids currently don't have any orientation. Up = Vector3.Up } }; entities.Add(entity); sourceFiles.Add(tempSourcefilename); } sourceVoxelFiles = sourceFiles.ToArray(); sourceEntities = entities.ToArray(); }
private void SubtractAsteroidVolumeFrom(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(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.Content, 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); if (volume > 0) { byte existingVolume = newCache.Content(ref p); if (existingVolume - volume < 0) { volume = 0; } else { volume = (byte)(existingVolume - volume); } newCache.Content(ref p, volume); } } } } newAsteroid.Storage.WriteRange(newCache, MyStorageDataTypeFlags.ContentAndMaterial, newBlock, newBlock + cacheSize - 1); } } } }
/// <summary> /// Starts the explosion. /// </summary> /// <param name="damage"></param> /// <param name="type"></param> /// <param name="explosionSphere"></param> /// <param name="lifespanInMiliseconds"></param> /// <param name="explosionForceDirection"></param> /// <param name="groupMask"></param> /// <param name="createExplosionDebris"></param> /// <param name="cascadeLevel"></param> /// <param name="hitEntity"></param> /// <param name="particleScale"></param> /// <param name="ownerEntity"></param> /// <param name="affectVoxels"></param> /// <param name="applyForceAndDamage"></param> /// <param name="createDecals"></param> /// <param name="direction">If applicable, gives the direction of the explosion, e.g. when it was caused by a missile (with its moving direction).</param> public void Start(ref MyExplosionInfo explosionInfo) { //MyCommonDebugUtils.AssertDebug(explosionInfo.ExplosionSphere.Radius <= MyExplosionsConstants.EXPLOSION_RADIUS_MAX); MyCommonDebugUtils.AssertDebug(explosionInfo.ExplosionSphere.Radius > 0); MyRender.GetRenderProfiler().StartProfilingBlock("MyExplosion.Start"); m_explosionSphere = explosionInfo.ExplosionSphere; m_elapsedMiliseconds = 0; m_lifespanInMiliseconds = explosionInfo.LifespanMiliseconds; if (explosionInfo.PlaySound) { MyRender.GetRenderProfiler().StartProfilingBlock("Sound"); // Play explosion sound if (m_explosionCue != null && m_explosionCue.Value.IsPlaying) { m_explosionCue.Value.Stop(SharpDX.XACT3.StopFlags.Immediate); } m_explosionCue = MyAudio.AddCue3D(GetCueEnumByExplosionType(explosionInfo.ExplosionType), m_explosionSphere.Center, Vector3.Zero, Vector3.Zero, Vector3.Zero); MyRender.GetRenderProfiler().EndProfilingBlock(); } MyRender.GetRenderProfiler().StartProfilingBlock("Light"); // Light of explosion /* * m_light = MyLights.AddLight(); * if (m_light != null) * { * m_light.Start(MyLight.LightTypeEnum.PointLight, m_explosionSphere.Center, MyExplosionsConstants.EXPLOSION_LIGHT_COLOR, 1, Math.Min(m_explosionSphere.Radius * 8.0f, MyLightsConstants.MAX_POINTLIGHT_RADIUS)); * m_light.Intensity = 2.0f; * } */ MyRender.GetRenderProfiler().EndProfilingBlock(); // close explosion check bool close = IsExplosionClose(explosionInfo.ExplosionSphere); MyParticleEffectsIDEnum newParticlesType; switch (explosionInfo.ExplosionType) { case MyExplosionTypeEnum.SMALL_SHIP_EXPLOSION: // Create metal debris objects thrown from the explosion // This must be called before ApplyExplosionForceAndDamage (because there we apply impulses to the debris) // Throw a lot of debrises, more than only if some metalic object is hit (because this is destruction of a ship) //MyPhysObjectExplosionDebrises.CreateExplosionDebris(m_explosionSphere.Center, 1); newParticlesType = MyParticleEffectsIDEnum.Explosion_Smallship; break; case MyExplosionTypeEnum.MISSILE_EXPLOSION: newParticlesType = // ? MyParticleEffectsIDEnum.Explosion_Missile_Close MyParticleEffectsIDEnum.Explosion_Missile; break; case MyExplosionTypeEnum.BOMB_EXPLOSION: case MyExplosionTypeEnum.GRAVITY_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_Bomb; break; case MyExplosionTypeEnum.AMMO_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_Ammo; break; case MyExplosionTypeEnum.BLASTER_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_Blaster; break; case MyExplosionTypeEnum.BIOCHEM_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_BioChem; break; case MyExplosionTypeEnum.EMP_EXPLOSION: case MyExplosionTypeEnum.FLASH_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_EMP; break; case MyExplosionTypeEnum.METEOR_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_Meteor; break; case MyExplosionTypeEnum.NUCLEAR_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_Nuclear; break; case MyExplosionTypeEnum.PLASMA_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_Plasma; break; case MyExplosionTypeEnum.SMALL_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_SmallPrefab; break; case MyExplosionTypeEnum.LARGE_SHIP_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_Huge; break; case MyExplosionTypeEnum.LARGE_PREFAB_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_Large; break; case MyExplosionTypeEnum.MEDIUM_PREFAB_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_Medium; break; case MyExplosionTypeEnum.ASTEROID_EXPLOSION: newParticlesType = MyParticleEffectsIDEnum.Explosion_Asteroid; break; default: throw new System.NotImplementedException(); break; } if (explosionInfo.Damage > 0) { MyRender.GetRenderProfiler().StartProfilingBlock("Voxel or collision"); // If explosion sphere intersects a voxel map, we need to cut out a sphere, spawn debrises, etc MyVoxelMap voxelMap = explosionInfo.AffectVoxels && explosionInfo.EmpDamage == 0 ? MyVoxelMaps.GetOverlappingWithSphere(ref m_explosionSphere) : null; if (voxelMap != null) { // Dirty explosion with a lot of dust MyMwcVoxelMaterialsEnum?voxelMaterial = null; float voxelContentRemovedInPercent = 0; bool createDebris = true; // We want to create debris if (explosionInfo.HitEntity != null) // but not when we hit prefab { createDebris &= explosionInfo.HitEntity is MyVoxelMap; } //cut off BoundingSphere voxelExpSphere = new BoundingSphere(explosionInfo.VoxelExplosionCenter, m_explosionSphere.Radius * explosionInfo.VoxelCutoutScale); if (MyVoxelGenerator.CutOutSphereFast(voxelMap, voxelExpSphere, out voxelContentRemovedInPercent, out voxelMaterial, (explosionInfo.OwnerEntity is MySmallShip && explosionInfo.OwnerEntity == Managers.Session.MySession.PlayerShip), MyFakes.VOXELS_REMOVE_RATIO)) { if (explosionInfo.HitEntity is MyVoxelMap) { HUD.MyHud.ShowIndestructableAsteroidNotification(); } createDebris = false; // and no debris when voxel is indestructible } // Only if at least something was removed from voxel map // If voxelContentRemovedInPercent is more than zero than also voxelMaterial shouldn't be null, but I rather check both of them. if ((voxelContentRemovedInPercent > 0) && (voxelMaterial != null)) { //remove decals MyDecals.HideTrianglesAfterExplosion(voxelMap, ref voxelExpSphere); MyRender.GetRenderProfiler().StartProfilingBlock("CreateDebris"); if (explosionInfo.CreateDebris && (createDebris || explosionInfo.ForceDebris) && MyRenderConstants.RenderQualityProfile.ExplosionDebrisCountMultiplier > 0) { // Create debris rocks thrown from the explosion // This must be called before ApplyExplosionForceAndDamage (because there we apply impulses to the debris) MyExplosionDebrisVoxel.CreateExplosionDebris(ref voxelExpSphere, voxelContentRemovedInPercent, voxelMaterial.Value, explosionInfo.GroupMask, voxelMap); } MyRender.GetRenderProfiler().EndProfilingBlock(); MyRender.GetRenderProfiler().StartProfilingBlock("CreateParticleEffect"); MyParticleEffect explosionEffect = MyParticlesManager.CreateParticleEffect((int)MyParticleEffectsIDEnum.MaterialExplosion_Destructible); explosionEffect.WorldMatrix = Matrix.CreateTranslation(voxelExpSphere.Center); explosionEffect.UserRadiusMultiplier = voxelExpSphere.Radius; MyRender.GetRenderProfiler().EndProfilingBlock(); } } MyRender.GetRenderProfiler().EndProfilingBlock(); } if (explosionInfo.Damage > 0) { // Create dirt decals in player's cockpit glass MyRender.GetRenderProfiler().StartProfilingBlock("Cockpit Decals"); CreateDirtDecalOnCockpitGlass(ref m_explosionSphere); MyRender.GetRenderProfiler().EndProfilingBlock(); } if (DEBUG_EXPLOSIONS) { MyRender.GetRenderProfiler().EndProfilingBlock(); return; } if (explosionInfo.Damage > 0) { BoundingSphere influenceExplosionSphere = m_explosionSphere; influenceExplosionSphere.Radius *= MyExplosionsConstants.EXPLOSION_RADIUS_MULTPLIER_FOR_IMPULSE; for (int i = 0; i < explosionInfo.CascadeLevel; i++) { influenceExplosionSphere.Radius *= MyExplosionsConstants.EXPLOSION_CASCADE_FALLOFF; } // Throws surrounding objects away from centre of the explosion. if (explosionInfo.ApplyForceAndDamage) { if (explosionInfo.ExplosionType == MyExplosionTypeEnum.LARGE_PREFAB_EXPLOSION || explosionInfo.ExplosionType == MyExplosionTypeEnum.LARGE_SHIP_EXPLOSION || explosionInfo.ExplosionType == MyExplosionTypeEnum.MEDIUM_PREFAB_EXPLOSION) { DisableContainedDummyParticles(ref explosionInfo); } explosionInfo.StrengthImpulse = MyExplosionsConstants.EXPLOSION_STRENGTH_IMPULSE * m_explosionSphere.Radius / 20; explosionInfo.StrengthAngularImpulse = MyExplosionsConstants.EXPLOSION_STRENGTH_ANGULAR_IMPULSE; explosionInfo.HitEntity = explosionInfo.HitEntity != null?explosionInfo.HitEntity.GetBaseEntity() : null; MyRender.GetRenderProfiler().StartProfilingBlock("ApplyExplosionForceAndDamage"); MyEntities.ApplyExplosionForceAndDamage(ref explosionInfo); MyRender.GetRenderProfiler().EndProfilingBlock(); } // Look for objects in explosion radius BoundingBox boundingBox; BoundingBox.CreateFromSphere(ref influenceExplosionSphere, out boundingBox); //if (explosionInfo.CreateDecals && explosionInfo.Direction.HasValue && explosionInfo.EmpDamage == 0) //{ // CreateDecals(explosionInfo.Direction.Value); //} } if (explosionInfo.CreateParticleEffect) { MyRender.GetRenderProfiler().StartProfilingBlock("Particles"); if (explosionInfo.CustomEffect != null) { if (explosionInfo.CustomEffect.ParticleID == 0) { explosionInfo.CustomEffect.ParticleID = (int)newParticlesType; } //Reload effect explosionInfo.CustomEffect.Enabled = false; explosionInfo.CustomEffect.Enabled = true; } else { // Explosion particles GenerateExplosionParticles(newParticlesType, m_explosionSphere, explosionInfo.ParticleScale); } MyRender.GetRenderProfiler().EndProfilingBlock(); } MyRender.GetRenderProfiler().EndProfilingBlock(); /* * // When MyAmmoBase entity is closed to explosion it will explode * if (entity is MyAmmoBase) * { * (entity as MyAmmoBase).ExplodeCascade(cascadeLevel + 1); * } */ // Smut decals - must be called after the explosion, after voxels are cutted out /*if ((intersection.PhysObject is MyVoxelMap) == false) * { * if (intersection.PhysObject is MyCockpitGlass) * { * // Change phys object so rest of the code will think we hit the parent * // Same fix is in projectile too - because cockpit glass is only helper object, we don't use it for real rendering and stuff * // And if not changed, it can make problem in "phys object decals" * intersection.PhysObject = intersection.PhysObject.Parent; * } * * // Create explosion smut decal on model we hit by this missile * MyDecals.Add( * MyDecalTexturesEnum.ExplosionSmut, * MyMwcUtils.GetRandomFloat(m_explosionSphere.Radius * 0.7f, m_explosionSphere.Radius * 1.3f), * MyMwcUtils.GetRandomRadian(), * GetSmutDecalRandomColor(), * true, * ref intersection); * } * else * { * // Creating explosion smut decal on voxel is more complicated than on voxel. We will project few lines * // from explosion epicentrum to the surounding world (random directions) and place decal where intersection detected. * //if (knownMissileDirection != null) * //{ * // MyLine linePrologned = new MyLine(knownIntersection.Value.IntersectionPointInObjectSpace, * // knownIntersection.Value.IntersectionPointInObjectSpace + knownMissileDirection.Value * MyExplosionsConstants.EXPLOSION_RANDOM_RADIUS_MAX * 2, * // true); * // MyLineTriangleIntersectionResult intersectionForSmut = knownIntersection.Value.VoxelMap.GetIntersectionWithLine(ref linePrologned); * // if (intersectionForSmut.Found == true) * // { * // MyDecals.Add( * // MyDecalTexturesEnum.ExplosionSmut, * // MyMwcUtils.GetRandomFloat(m_explosionSphere.Radius * 0.5f, m_explosionSphere.Radius * 1.0f), * // MyMwcUtils.GetRandomRadian(), * // GetSmutDecalRandomColor(), * // false, * // ref intersectionForSmut); * // } * //} * }*/ // Generate dust particles that will stay in place of the explosion //doesnt look good in final //GenerateStatisDustParticles(m_explosionSphere); }
// Return reference to a voxel map that intersects with the specified box. If not intersection, null is returned. // We don't look for closest intersection - so we stop on first intersection found. // Params: // localBoundingBox - local bounding box, we transform it to VoxelMap orientation // boundingBoxWorldPosition - position of bounding box in world coordinates public static MyVoxelMap GetIntersectionWithBox(ref BoundingBox localBoundingBox, ref Vector3 boundingBoxWorldPosition, MyVoxelMap selected) { for (int i = 0; i < m_voxelMaps.Count; i++) { if (selected == null || m_voxelMaps[i] == selected) { MyVoxelMap voxelMap = m_voxelMaps[i]; Matrix world = Matrix.CreateWorld(boundingBoxWorldPosition, voxelMap.WorldMatrix.Forward, voxelMap.WorldMatrix.Up); BoundingBox worldBoundingBox = localBoundingBox.Transform(world); if (voxelMap.IsBoxIntersectingBoundingBoxOfThisVoxelMap(ref worldBoundingBox)) { return(voxelMap); } } } // No intersection found return(null); }
public static MyStorageBase LoadFromFile(MyVoxelMap voxelMap, string absoluteFilePath) { if (!MyFileSystem.FileExists(absoluteFilePath)) { var oldPath = Path.ChangeExtension(absoluteFilePath, "vox"); UpdateFileFormat(oldPath); Debug.Assert(MyFileSystem.FileExists(absoluteFilePath)); } Debug.Assert(absoluteFilePath.EndsWith(MyVoxelConstants.FILE_EXTENSION)); byte[] compressedData = null; using (var file = MyFileSystem.OpenRead(absoluteFilePath)) { compressedData = new byte[file.Length]; file.Read(compressedData, 0, compressedData.Length); } return Load(voxelMap, compressedData, Path.GetFileNameWithoutExtension(absoluteFilePath)); }
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); } } } }
//public static event OnVoxelShapeSizeChanged OnVoxelShapeSize; //public static event OnVoxelShapeDistanceChanged OnVoxelShapeDistance; public static void HandleInput(MyGuiInput input) { // exit voxel hand using this key if (input.IsEditorControlNewPressed(MyEditorControlEnums.VOXEL_HAND)) { SwitchEnabled(); } if (m_Enabled == false || !IsAnyEditorActive()) { return; } m_applyToVoxelMap = null; //here possible change if ((input.IsEditorControlNewPressed(MyEditorControlEnums.PRIMARY_ACTION_KEY) || input.IsAnyShiftKeyPressed() && input.IsEditorControlPressed(MyEditorControlEnums.PRIMARY_ACTION_KEY)) && (m_timeFromLastShaping >= MyVoxelConstants.VOXEL_HAND_SHAPING_INTERVAL || MyFakes.RAPID_VOXEL_HAND_SHAPING_ENABLED || MyFakes.MWBUILDER)) { m_timeFromLastShaping = 0; if (DetachedVoxelHand != null && !input.IsKeyPress(Keys.Space)) { return; } MyVoxelMap voxelMap = null; if (VoxelHandShape is MyVoxelHandSphere) { MyVoxelHandSphere sphere = (MyVoxelHandSphere)VoxelHandShape; BoundingSphere vol = sphere.WorldVolume; voxelMap = MyVoxelMaps.GetIntersectionWithSphere(ref vol, SelectedVoxelMap); } else if (VoxelHandShape is MyVoxelHandBox) { MyVoxelHandBox box = (MyVoxelHandBox)VoxelHandShape; BoundingBox localBoundingBox = box.GetLocalBoundingBox(); Vector3 boxWorldPosition = box.GetPosition(); voxelMap = MyVoxelMaps.GetIntersectionWithBox(ref localBoundingBox, ref boxWorldPosition, SelectedVoxelMap); } else if (VoxelHandShape is MyVoxelHandCuboid) { MyVoxelHandCuboid cuboid = (MyVoxelHandCuboid)VoxelHandShape; BoundingBox localBoundingBox = cuboid.GetLocalBoundingBox(); Vector3 boxWorldPosition = cuboid.GetPosition(); voxelMap = MyVoxelMaps.GetIntersectionWithBox(ref localBoundingBox, ref boxWorldPosition, SelectedVoxelMap); } else if (VoxelHandShape is MyVoxelHandCylinder) { MyVoxelHandCylinder cylinder = (MyVoxelHandCylinder)VoxelHandShape; BoundingBox localBoundingBox = cylinder.GetLocalBoundingBox(); Vector3 boxWorldPosition = cylinder.GetPosition(); voxelMap = MyVoxelMaps.GetIntersectionWithBox(ref localBoundingBox, ref boxWorldPosition, SelectedVoxelMap); } else { System.Diagnostics.Debug.Assert(false); } if (voxelMap != null) { m_applyToVoxelMap = voxelMap; } } //////////////////////////////////////////////////////////////////////////////////////////////////////////// // Change size of asteroid tool from camera //////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * if (input.IsAnyShiftKeyPressed()) * { * if (input.PreviousMouseScrollWheelValue() > input.MouseScrollWheelValue()) * { * SetVoxelSize(MyEditorVoxelHand.VoxelHandShape.GetShapeSize() - MyVoxelConstants.VOXEL_HAND_SIZE_STEP); * } * else if (input.PreviousMouseScrollWheelValue() < input.MouseScrollWheelValue()) * { * SetVoxelSize(MyEditorVoxelHand.VoxelHandShape.GetShapeSize() + MyVoxelConstants.VOXEL_HAND_SIZE_STEP); * } * * } * * //////////////////////////////////////////////////////////////////////////////////////////////////////////// * // Change distance of asteroid tool from camera * //////////////////////////////////////////////////////////////////////////////////////////////////////////// * * if (input.IsAnyControlPress()) * { * if (input.PreviousMouseScrollWheelValue() > input.MouseScrollWheelValue()) * { * SetShapeDistance(GetShapeDistance() - MyVoxelConstants.VOXEL_HAND_DISTANCE_STEP); * * } * else if (input.PreviousMouseScrollWheelValue() < input.MouseScrollWheelValue()) * { * SetShapeDistance(GetShapeDistance() + MyVoxelConstants.VOXEL_HAND_DISTANCE_STEP); * } * } */ }
public void RotateAsteroid(Quaternion quaternion) { var sourceFile = SourceVoxelFilepath ?? VoxelFilepath; var asteroid = new MyVoxelMap(); asteroid.Load(sourceFile); var newAsteroid = new MyVoxelMap(); var newSize = asteroid.Size; newAsteroid.Create(newSize, SpaceEngineersCore.Resources.GetDefaultMaterialIndex()); Vector3I block; var halfSize = asteroid.Storage.Size / 2; // Don't use anything smaller than 64 for smaller voxels, as it trashes the cache. var cacheSize = new Vector3I(64); var halfCacheSize = new Vector3I(32); // This should only be used for the Transform, not the cache. // read the asteroid in chunks of 64 to avoid the Arithmetic overflow issue. for (block.Z = 0; block.Z < asteroid.Storage.Size.Z; block.Z += 64) { for (block.Y = 0; block.Y < asteroid.Storage.Size.Y; block.Y += 64) { for (block.X = 0; block.X < asteroid.Storage.Size.X; block.X += 64) { #region source voxel var cache = new MyStorageData(); cache.Resize(cacheSize); // LOD1 is not detailed enough for content information on asteroids. asteroid.Storage.ReadRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, block, block + cacheSize - 1); #endregion #region target Voxel // the block is a cubiod. The entire space needs to rotate, to be able to gauge where the new block position starts from. var newBlockMin = Vector3I.Transform(block - halfSize, quaternion) + halfSize; var newBlockMax = Vector3I.Transform(block + 64 - halfSize, quaternion) + halfSize; var newBlock = Vector3I.Min(newBlockMin, newBlockMax); var newCache = new MyStorageData(); newCache.Resize(cacheSize); newAsteroid.Storage.ReadRange(newCache, MyStorageDataTypeFlags.ContentAndMaterial, 0, newBlock, newBlock + cacheSize - 1); #endregion bool changed = false; 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 cellMaterial = cache.Material(ref p); var newP1 = Vector3I.Transform(p - halfCacheSize, quaternion) + halfCacheSize; var newP2 = Vector3I.Transform(p + 1 - halfCacheSize, quaternion) + halfCacheSize; var newP = Vector3I.Min(newP1, newP2); newCache.Content(ref newP, volume); newCache.Material(ref newP, cellMaterial); changed = true; } } } if (changed) { newAsteroid.Storage.WriteRange(newCache, MyStorageDataTypeFlags.ContentAndMaterial, newBlock, newBlock + cacheSize - 1); } } } } var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension); newAsteroid.Save(tempfilename); SourceVoxelFilepath = tempfilename; }
public static bool UpdateVoxelMapScript(MyVoxelMap voxelMap) { if (MyHud.ContainsTextForEntity(voxelMap)) { if (m_outpostReached == false) { if (Vector3.Distance(MySession.PlayerShip.GetPosition(), voxelMap.GetPosition()) < REMOVE_FROM_HUD_POSSIBLE_OUTPOST_DISTANCE) { MyHud.RemoveText(voxelMap); } } else { MyHud.RemoveText(voxelMap); } } return true; }