public override void InitializeAsync() { _asyncWorker = new BackgroundWorker { WorkerSupportsCancellation = true }; _asyncWorker.DoWork += delegate { if (!_isLoadingAsync) { _isLoadingAsync = true; IsBusy = true; // TODO: planet details _voxelMap.RefreshAssets(); _contentCenter = _voxelMap.ContentCenter; Center = new Vector3D(_contentCenter.X + 0.5f + PositionX, _contentCenter.Y + 0.5f + PositionY, _contentCenter.Z + 0.5f + PositionZ); IsBusy = false; _isLoadingAsync = false; } }; _asyncWorker.RunWorkerAsync(); }
public void LoadDetailsSync() { ReadVoxelDetails(SourceVoxelFilepath ?? VoxelFilepath); if (_voxelMap != null && (MaterialAssets == null || MaterialAssets.Count == 0)) { Dictionary <string, long> details = _voxelMap.RefreshAssets(); _contentBounds = _voxelMap.BoundingContent; _inflatedContentBounds = _voxelMap.InflatedBoundingContent; _voxCells = _voxelMap.VoxCells; Center = new Vector3D(_voxelMap.ContentCenter.X + 0.5f + PositionX, _voxelMap.ContentCenter.Y + 0.5f + PositionY, _voxelMap.ContentCenter.Z + 0.5f + PositionZ); var sum = details.Values.ToList().Sum(); var list = new List <VoxelMaterialAssetModel>(); foreach (var kvp in details) { list.Add(new VoxelMaterialAssetModel { MaterialName = kvp.Key, Volume = (double)kvp.Value / 255, Percent = (double)kvp.Value / (double)sum }); } MaterialAssets = list; } }
public override void InitializeAsync() { _asyncWorker = new BackgroundWorker { WorkerSupportsCancellation = true }; _asyncWorker.DoWork += delegate { if (!_isLoadingAsync && (MaterialAssets == null || MaterialAssets.Count == 0)) { _isLoadingAsync = true; IsBusy = true; Dictionary <string, long> details; details = _voxelMap.RefreshAssets(); _contentBounds = _voxelMap.BoundingContent; _voxCells = _voxelMap.VoxCells; Center = new Vector3D(_contentBounds.Center.X + 0.5f + PositionX, _contentBounds.Center.Y + 0.5f + PositionY, _contentBounds.Center.Z + 0.5f + PositionZ); var sum = details.Values.ToList().Sum(); var list = new List <VoxelMaterialAssetModel>(); foreach (var kvp in details) { list.Add(new VoxelMaterialAssetModel { MaterialName = kvp.Key, Volume = (double)kvp.Value / 255, Percent = (double)kvp.Value / (double)sum }); } MaterialAssets = list; IsBusy = false; _isLoadingAsync = false; } }; _asyncWorker.RunWorkerCompleted += delegate { RaisePropertyChanged(() => Size); RaisePropertyChanged(() => ContentSize); RaisePropertyChanged(() => ContentBounds); RaisePropertyChanged(() => Center); RaisePropertyChanged(() => VoxCells); RaisePropertyChanged(() => Volume); }; _asyncWorker.RunWorkerAsync(); }
public void SliceHalfExecuted() { MainViewModel.IsBusy = true; var sourceFile = DataModel.SourceVoxelFilepath ?? DataModel.VoxelFilepath; var asteroid = new MyVoxelMap(); asteroid.Load(sourceFile); asteroid.RefreshAssets(); var height = asteroid.BoundingContent.Size.Y + 1; // remove the Top half. asteroid.RemoveMaterial(null, null, (int)Math.Round(asteroid.ContentCenter.Y, 0), asteroid.Size.Y, null, null); var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension); asteroid.Save(tempfilename); var newFilename = MainViewModel.CreateUniqueVoxelStorageName(DataModel.Name); var posOrient = DataModel.PositionAndOrientation.HasValue ? DataModel.PositionAndOrientation.Value : new MyPositionAndOrientation(); posOrient.Position.y += height; // genreate a new Asteroid entry. var newEntity = new MyObjectBuilder_VoxelMap { EntityId = SpaceEngineersApi.GenerateEntityId(IDType.ASTEROID), PersistentFlags = MyPersistentEntityFlags2.CastShadows | MyPersistentEntityFlags2.InScene, StorageName = Path.GetFileNameWithoutExtension(newFilename), PositionAndOrientation = new MyPositionAndOrientation { Position = posOrient.Position, Forward = posOrient.Forward, Up = posOrient.Up } }; var structure = MainViewModel.AddEntity(newEntity); ((StructureVoxelModel)structure).UpdateNewSource(asteroid, tempfilename); // Set the temporary file location of the Source Voxel, as it hasn't been written yet. MainViewModel.IsModified = true; MainViewModel.IsBusy = false; }
/// <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}"); }