use bevy::color::palettes::basic::{BLACK, RED, YELLOW}; use bevy::color::palettes::css::GREEN; use bevy::math::{DQuat, DVec3, Vec3}; use bevy::pbr::wireframe::Wireframe; use bevy::prelude::*; use bevy::render::mesh::{Indices, PrimitiveTopology}; use bevy::render::render_asset::RenderAssetUsages; use bevy_egui::egui::emath::Numeric; use bevy_render::prelude::*; use crate::helper::large_transform::DoubleTransform; use crate::systems::voxels::structure::{ChunkEntities, OctreeNode, SparseVoxelOctree}; pub fn visualize_octree( mut gizmos: Gizmos, camera_query: Query<&DoubleTransform, With>, octree_query: Query<(&SparseVoxelOctree, &DoubleTransform)>, ) { let camera_tf = camera_query.single(); // your "real" camera position in double precision let camera_pos = camera_tf.translation; // DVec3 for (octree, octree_tf) in octree_query.iter() { let octree_world_pos = octree_tf.translation; visualize_recursive( &mut gizmos, &octree.root, octree_world_pos, // octree’s root center octree.size, octree.max_depth, camera_pos, ); } } fn visualize_recursive( gizmos: &mut Gizmos, node: &OctreeNode, node_center: DVec3, node_size: f64, depth: u32, camera_pos: DVec3, ) { if depth == 0 { return; } // If you want to draw the bounding box of this node: /*let half = node_size as f32 * 0.5;*/ // Convert double center -> local f32 position let center_f32 = (node_center - camera_pos).as_vec3(); // A quick approach: draw a wireframe cube by drawing lines for each edge // Or use "cuboid gizmo" methods in future bevy versions that might exist. /*draw_wire_cube(gizmos, center_f32, half, Color::YELLOW);*/ gizmos.cuboid( Transform::from_translation(center_f32).with_scale(Vec3::splat(node_size as f32)), BLACK, ); // Recurse children if let Some(children) = &node.children { let child_size = node_size / 2.0; for (i, child) in children.iter().enumerate() { let offset_x = if (i & 1) == 1 { child_size / 2.0 } else { -child_size / 2.0 }; let offset_y = if (i & 2) == 2 { child_size / 2.0 } else { -child_size / 2.0 }; let offset_z = if (i & 4) == 4 { child_size / 2.0 } else { -child_size / 2.0 }; let child_center = DVec3::new( node_center.x + offset_x, node_center.y + offset_y, node_center.z + offset_z, ); visualize_recursive( gizmos, child, child_center, child_size, depth - 1, camera_pos, ); } } } #[allow(dead_code)] pub fn draw_grid( mut gizmos: Gizmos, camera_query: Query<&DoubleTransform, With>, octree_query: Query<(&SparseVoxelOctree, &DoubleTransform)>, ) { // 1) Get the camera’s double transform for offset let camera_tf = camera_query.single(); let camera_pos = camera_tf.translation; // DVec3 for (octree, octree_dtf) in octree_query.iter() { // 2) Octree’s double position let octree_pos = octree_dtf.translation; // e.g. [100_000, 0, 0] in double space // 3) Compute spacing in f64 let grid_spacing = octree.get_spacing_at_depth(octree.max_depth) as f64; let grid_size = (octree.size / grid_spacing) as i32; // 4) Start position in local "octree space" // We'll define the bounding region from [-size/2, +size/2] let half_size = octree.size * 0.5; let start_position = -half_size; // f64 // 5) Loop over lines for i in 0..=grid_size { // i-th line offset let offset = i as f64 * grid_spacing; // a) Lines along Z // from (start_position + offset, 0, start_position) // to (start_position + offset, 0, start_position + grid_size * spacing) { let x = start_position + offset; let z1 = start_position; let z2 = start_position + (grid_size as f64 * grid_spacing); // Convert these points to "world double" by adding octree_pos let p1_d = DVec3::new(x, 0.0, z1) + octree_pos; let p2_d = DVec3::new(x, 0.0, z2) + octree_pos; // Then offset by camera_pos, convert to f32 let p1_f32 = (p1_d - camera_pos).as_vec3(); let p2_f32 = (p2_d - camera_pos).as_vec3(); // Draw the line gizmos.line(p1_f32, p2_f32, Color::WHITE); } // b) Lines along X // from (start_position, 0, start_position + offset) // to (start_position + grid_size * spacing, 0, start_position + offset) { let z = start_position + offset; let x1 = start_position; let x2 = start_position + (grid_size as f64 * grid_spacing); let p1_d = DVec3::new(x1, 0.0, z) + octree_pos; let p2_d = DVec3::new(x2, 0.0, z) + octree_pos; let p1_f32 = (p1_d - camera_pos).as_vec3(); let p2_f32 = (p2_d - camera_pos).as_vec3(); gizmos.line(p1_f32, p2_f32, Color::WHITE); } } } } /*#[derive(Component)] pub struct GridMarker; pub fn draw_grid( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, query: Query<(Entity, &SparseVoxelOctree)>, // Query to access the octree grid_query: Query>, // Query to find existing grid entities ) { for (_, octree) in query.iter() { if octree.show_world_grid { // If grid should be shown, check if it already exists if grid_query.iter().next().is_none() { // Grid doesn't exist, so create it let grid_spacing = octree.get_spacing_at_depth(octree.max_depth) as f32; // Get spacing at the specified depth let grid_size = (octree.size / grid_spacing as f64) as i32; // Determine the number of lines needed let mut positions = Vec::new(); let mut indices = Vec::new(); // Calculate the start position to center the grid let start_position = -(octree.size as f32 / 2.0); // Create lines along the X and Z axes based on calculated spacing for i in 0..=grid_size { // Lines along the Z-axis positions.push([start_position + i as f32 * grid_spacing, 0.0, start_position]); positions.push([start_position + i as f32 * grid_spacing, 0.0, start_position + grid_size as f32 * grid_spacing]); // Indices for the Z-axis lines let base_index = (i * 2) as u32; indices.push(base_index); indices.push(base_index + 1); // Lines along the X-axis positions.push([start_position, 0.0, start_position + i as f32 * grid_spacing]); positions.push([start_position + grid_size as f32 * grid_spacing, 0.0, start_position + i as f32 * grid_spacing]); // Indices for the X-axis lines let base_index_x = ((grid_size + 1 + i) * 2) as u32; indices.push(base_index_x); indices.push(base_index_x + 1); } // Create the line mesh let mut mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default()); mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions); mesh.insert_indices(Indices::U32(indices)); let color = bevy::color::Color::srgba(204.0 / 255.0, 0.0, 218.0 / 255.0, 15.0 / 255.0); // Spawn the entity with the line mesh commands.spawn(PbrBundle { mesh: meshes.add(mesh).into(), material: materials.add(StandardMaterial { base_color: Color::WHITE, unlit: true, // Makes the lines visible without lighting ..Default::default() }).into(), transform: Transform::default(), ..Default::default() }) .insert(GridMarker); // Add a marker component to identify the grid } } else { // If grid should not be shown, remove any existing grid for grid_entity in grid_query.iter() { commands.entity(grid_entity).despawn(); } } } } */ /*#[derive(Component)] pub struct BuildVisualization; #[derive(Debug)] pub struct EphemeralLine { pub start: Vec3, pub end: Vec3, pub color: Color, pub time_left: f32, // in seconds } #[derive(Resource, Default)] pub struct EphemeralLines { pub lines: Vec, } pub fn ephemeral_lines_system( mut lines: ResMut, mut gizmos: Gizmos, time: Res