2025-02-08 18:03:00 +01:00

360 lines
13 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<Camera>>,
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, // octrees 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<Camera>>,
octree_query: Query<(&SparseVoxelOctree, &DoubleTransform)>,
) {
// 1) Get the cameras 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) Octrees 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<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
query: Query<(Entity, &SparseVoxelOctree)>, // Query to access the octree
grid_query: Query<Entity, With<GridMarker>>, // 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<EphemeralLine>,
}
pub fn ephemeral_lines_system(
mut lines: ResMut<EphemeralLines>,
mut gizmos: Gizmos,
time: Res<Time>,
) {
let dt = time.delta_secs();
// Retain only those with time_left > 0, and while they're active, draw them
lines.lines.retain_mut(|line| {
line.time_left -= dt;
if line.time_left > 0.0 {
// Draw the line with gizmos
gizmos.line(line.start, line.end, line.color);
// Keep it
true
} else {
// Times up, discard
false
}
});
}*/
// System that draws wireframe boxes around each chunk's bounding region.
pub fn debug_draw_chunks_system(
chunk_entities: Res<ChunkEntities>,
// If your chunk placement depends on the octree's transform
// query that. Otherwise you can skip if they're always at (0,0,0).
octree_query: Query<(&SparseVoxelOctree, &DoubleTransform)>,
// Optional: If you want large-world offset for camera, we can subtract camera position.
// If you don't have floating-origin logic, you can skip this.
camera_query: Query<&DoubleTransform, With<Camera>>,
mut gizmos: Gizmos,
) {
// We'll get the octree transform offset if we have only one octree.
// Adjust if you have multiple.
let (octree, octree_tf) = match octree_query.get_single() {
Ok(x) => x,
Err(_) => return,
};
// 1) Determine the world size of a single voxel
let step = octree.get_spacing_at_depth(octree.max_depth);
// chunk_size in world units = 16 voxels * step
let chunk_size_world = octree.get_chunk_size() as f64 * step;
// 2) We'll also get the octree's offset in double precision
let octree_pos_d = octree_tf.translation;
// If you want a floating origin approach, subtract the camera's double position:
let camera_tf = match camera_query.get_single() {
Ok(tf) => tf,
Err(_) => return,
};
let camera_pos_d = camera_tf.translation;
// For each chunk coordinate
for (&(cx, cy, cz), _entity) in chunk_entities.map.iter() {
// 4) Chunk bounding box in double precision
let chunk_min_d = octree_pos_d
+ DVec3::new(
cx as f64 * chunk_size_world,
cy as f64 * chunk_size_world,
cz as f64 * chunk_size_world,
);
let chunk_max_d = chunk_min_d + DVec3::splat(chunk_size_world);
// 5) Convert to local f32 near the camera
let min_f32 = (chunk_min_d - camera_pos_d).as_vec3();
let max_f32 = (chunk_max_d - camera_pos_d).as_vec3();
// 6) Draw ephemeral lines for the box
draw_wire_cube(&mut gizmos, min_f32, max_f32, Color::from(YELLOW));
}
}
/// Helper function to draw a wireframe box from `min` to `max` in ephemeral gizmos.
fn draw_wire_cube(
gizmos: &mut Gizmos,
min: Vec3,
max: Vec3,
color: Color,
) {
// corners
let c0 = Vec3::new(min.x, min.y, min.z);
let c1 = Vec3::new(max.x, min.y, min.z);
let c2 = Vec3::new(min.x, max.y, min.z);
let c3 = Vec3::new(max.x, max.y, min.z);
let c4 = Vec3::new(min.x, min.y, max.z);
let c5 = Vec3::new(max.x, min.y, max.z);
let c6 = Vec3::new(min.x, max.y, max.z);
let c7 = Vec3::new(max.x, max.y, max.z);
// edges
// bottom face
gizmos.line(c0, c1, color);
gizmos.line(c1, c3, color);
gizmos.line(c3, c2, color);
gizmos.line(c2, c0, color);
// top face
gizmos.line(c4, c5, color);
gizmos.line(c5, c7, color);
gizmos.line(c7, c6, color);
gizmos.line(c6, c4, color);
// verticals
gizmos.line(c0, c4, color);
gizmos.line(c1, c5, color);
gizmos.line(c2, c6, color);
gizmos.line(c3, c7, color);
}