/// <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}"); }
/// <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); }
/// <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); }