From 85699338a96630571fec99479c2c749c11edbf84 Mon Sep 17 00:00:00 2001 From: Elias Stepanik Date: Mon, 9 Jun 2025 21:44:47 +0200 Subject: [PATCH] Load and Unload System working --- .../plugins/environment/environment_plugin.rs | 4 - .../environment/systems/voxel_system.rs | 92 +++++++++++++++++-- .../plugins/environment/systems/voxels/lod.rs | 4 +- .../environment/systems/voxels/octree.rs | 2 +- .../environment/systems/voxels/structure.rs | 3 +- client/src/plugins/input/systems/voxels.rs | 33 ++++++- 6 files changed, 115 insertions(+), 23 deletions(-) diff --git a/client/src/plugins/environment/environment_plugin.rs b/client/src/plugins/environment/environment_plugin.rs index ffd533b..f6ae4e7 100644 --- a/client/src/plugins/environment/environment_plugin.rs +++ b/client/src/plugins/environment/environment_plugin.rs @@ -70,8 +70,4 @@ fn should_visualize_octree(octree_query: Query<&SparseVoxelOctree>,) -> bool { fn should_draw_grid(octree_query: Query<&SparseVoxelOctree>,) -> bool { octree_query.single().show_world_grid -} - -fn should_visualize_chunks(octree_query: Query<&SparseVoxelOctree>,) -> bool { - octree_query.single().show_chunks } \ No newline at end of file diff --git a/client/src/plugins/environment/systems/voxel_system.rs b/client/src/plugins/environment/systems/voxel_system.rs index 66948e5..72ed8da 100644 --- a/client/src/plugins/environment/systems/voxel_system.rs +++ b/client/src/plugins/environment/systems/voxel_system.rs @@ -1,32 +1,106 @@ +use std::path::Path; +use rayon::prelude::*; use crate::plugins::big_space::big_space_plugin::RootGrid; use crate::plugins::environment::systems::voxels::structure::*; use bevy::prelude::*; use bevy::render::mesh::*; use noise::{NoiseFn, Perlin}; +use rand::{thread_rng, Rng}; pub fn setup( mut commands: Commands, root: Res, ) { - let unit_size = 1.0_f32; + // Octree parameters + let unit_size = 1.0_f32; let octree_base_size = 64.0 * unit_size; - let octree_depth = 10; + let octree_depth = 10; - // 1. Create octree and wrap in Arc> for thread-safe generation - let mut octree = SparseVoxelOctree::new(octree_depth, octree_base_size, false, false, false); + let path = Path::new("octree.bin"); - // 2. Generate sphere in parallel, dropping the cloned Arc inside the function - let color = Color::rgb(0.2, 0.8, 0.2); - - generate_voxel_sphere(&mut octree, 110, color); - // 4. Spawn entity with both Transform and the real octree component + let mut octree = if path.exists() { + match SparseVoxelOctree::load_from_file(path) { + Ok(tree) => tree, + Err(err) => { + error!("failed to load octree: {err}"); + SparseVoxelOctree::new(octree_depth, octree_base_size, false, false, false) + } + } + } else { + let mut tree = SparseVoxelOctree::new(octree_depth, octree_base_size, false, false, false); + let color = Color::rgb(0.2, 0.8, 0.2); + // How many random spheres? + /*const NUM_SPHERES: usize = 5; + let mut rng = thread_rng(); + + for _ in 0..NUM_SPHERES { + let center = Vec3::new( + rng.gen_range(-1000.0..1000.0), + rng.gen_range(-1000.0..1000.0), + rng.gen_range(-1000.0..1000.0), + ); + + let radius = rng.gen_range(20..=150); // voxels + + generate_voxel_sphere_parallel(&mut tree, center, radius, color); + }*/ + + generate_voxel_sphere(&mut tree, 200, color); + tree + }; + + + + + // Attach octree to the scene graph commands.entity(root.0).with_children(|parent| { parent.spawn((Transform::default(), octree)); }); } +pub fn generate_voxel_sphere_parallel( + octree: &mut SparseVoxelOctree, + center: Vec3, + radius: i32, + color: Color, +) { + let step = octree.get_spacing_at_depth(octree.max_depth); + let radius_sq = radius * radius; + + // 1. Collect voxel positions in parallel + let voxels: Vec<(Vec3, Voxel)> = (-radius..=radius) + .into_par_iter() + .flat_map_iter(|ix| { + let dx2 = ix * ix; + (-radius..=radius).flat_map(move |iy| { + let dy2 = iy * iy; + let r2_xy = dx2 + dy2; + + if r2_xy > radius_sq { + return Vec::new(); // this (x,y) column is outside + } + + let max_z = ((radius_sq - r2_xy) as f32).sqrt() as i32; + (-max_z..=max_z).map(move |iz| { + let pos = Vec3::new( + center.x + ix as f32 * step, + center.y + iy as f32 * step, + center.z + iz as f32 * step, + ); + (pos, Voxel { color }) + }).collect::>() + }) + }) + .collect(); + + // 2. Single-threaded insert (keeps `SparseVoxelOctree` API unchanged) + for (pos, voxel) in voxels { + octree.insert(pos, voxel); + } +} + fn generate_voxel_sphere( octree: &mut SparseVoxelOctree, diff --git a/client/src/plugins/environment/systems/voxels/lod.rs b/client/src/plugins/environment/systems/voxels/lod.rs index f8360c5..df3577d 100644 --- a/client/src/plugins/environment/systems/voxels/lod.rs +++ b/client/src/plugins/environment/systems/voxels/lod.rs @@ -14,8 +14,8 @@ pub fn update_chunk_lods( // Borrow the octree only once to avoid repeated query lookups let mut tree = tree_q.single_mut(); - let max_depth = tree.max_depth; - let range_step = cfg.view_distance_chunks as f32 / max_depth as f32; + let max_depth = tree.max_depth - 1; + let range_step = cfg.view_distance_chunks as f32 / (max_depth as f32 - 1.0); let chunk_size = CHUNK_SIZE as f32 * tree.get_spacing_at_depth(max_depth); let mut changed = Vec::new(); diff --git a/client/src/plugins/environment/systems/voxels/octree.rs b/client/src/plugins/environment/systems/voxels/octree.rs index 1794ca3..be22069 100644 --- a/client/src/plugins/environment/systems/voxels/octree.rs +++ b/client/src/plugins/environment/systems/voxels/octree.rs @@ -20,7 +20,6 @@ impl SparseVoxelOctree { size, show_wireframe, show_world_grid, - show_chunks, dirty: Vec::new(), dirty_chunks: Default::default(), occupied_chunks: Default::default(), @@ -482,6 +481,7 @@ impl SparseVoxelOctree { self.dirty.clear(); self.dirty_chunks.clear(); self.occupied_chunks.clear(); + let voxels = Self::collect_voxels_from_node(&self.root, self.size); for (pos, _voxel, _depth) in voxels { let key = chunk_key_from_world(self, pos); diff --git a/client/src/plugins/environment/systems/voxels/structure.rs b/client/src/plugins/environment/systems/voxels/structure.rs index 06ab422..21457e1 100644 --- a/client/src/plugins/environment/systems/voxels/structure.rs +++ b/client/src/plugins/environment/systems/voxels/structure.rs @@ -42,7 +42,7 @@ pub struct OctreeNode { } /// Represents the root of the sparse voxel octree. /// Represents the root of the sparse voxel octree. -#[derive(Debug, Component, Serialize, Deserialize)] +#[derive(Debug, Component, Serialize, Deserialize, Clone)] pub struct SparseVoxelOctree { pub root: OctreeNode, @@ -50,7 +50,6 @@ pub struct SparseVoxelOctree { pub size: f32, pub show_wireframe: bool, pub show_world_grid: bool, - pub show_chunks: bool, #[serde(skip)] pub dirty: Vec, diff --git a/client/src/plugins/input/systems/voxels.rs b/client/src/plugins/input/systems/voxels.rs index cbc33ed..617f416 100644 --- a/client/src/plugins/input/systems/voxels.rs +++ b/client/src/plugins/input/systems/voxels.rs @@ -1,5 +1,7 @@ +use std::path::Path; use bevy::prelude::*; use crate::plugins::environment::systems::camera_system::CameraController; +use crate::plugins::environment::systems::voxels::octree; use crate::plugins::environment::systems::voxels::structure::*; ///TODO @@ -28,16 +30,37 @@ pub fn voxel_system( octree.show_world_grid = !octree.show_world_grid; } } - if keyboard_input.just_pressed(KeyCode::F4){ - for mut octree in octree_query.iter_mut() { - octree.show_chunks = !octree.show_chunks; - } - } + if keyboard_input.just_pressed(KeyCode::KeyQ) && window.cursor_options.visible == false{ for mut octree in octree_query.iter_mut() { octree.insert(transform.translation, Voxel::new(Color::srgb(1.0, 0.0, 0.0))); } } + if keyboard_input.just_pressed(KeyCode::F4){ + let path = Path::new("octree.bin"); + for octree in octree_query.iter() { + if let Err(e) = octree.save_to_file(path) { + error!("failed to save octree: {e}"); + } + } + } +/* if keyboard_input.just_pressed(KeyCode::F5){ + let path = Path::new("octree.bin"); + if path.exists() { + let path = Path::new("octree.bin"); + + let mut octree = if path.exists() { + match SparseVoxelOctree::load_from_file(path) { + Ok(tree) => tree, + Err(err) => { + error!("failed to load octree: {err}"); + } + } + } + + } + }*/ + // ======================= // 6) Building