1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::RayCastSource;
use bevy::prelude::*;
use std::marker::PhantomData;

#[derive(Component)]
pub struct DebugCursor<T> {
    _phantom: PhantomData<T>,
}
impl<T> Default for DebugCursor<T> {
    fn default() -> Self {
        DebugCursor {
            _phantom: PhantomData::default(),
        }
    }
}

#[derive(Component)]
pub struct DebugCursorTail<T> {
    _phantom: PhantomData<T>,
}
impl<T> Default for DebugCursorTail<T> {
    fn default() -> Self {
        DebugCursorTail {
            _phantom: PhantomData::default(),
        }
    }
}

#[derive(Component)]
pub struct DebugCursorMesh<T> {
    _phantom: PhantomData<T>,
}
impl<T> Default for DebugCursorMesh<T> {
    fn default() -> Self {
        DebugCursorMesh {
            _phantom: PhantomData::default(),
        }
    }
}

/// Updates the 3d cursor to be in the pointed world coordinates
#[allow(clippy::type_complexity)]
#[allow(clippy::too_many_arguments)]
pub fn update_debug_cursor<T: 'static + Send + Sync>(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
    added_sources_query: Query<&RayCastSource<T>, Added<RayCastSource<T>>>,
    mut cursor_query: Query<&mut GlobalTransform, With<DebugCursor<T>>>,
    mut cursor_tail_query: Query<
        &mut GlobalTransform,
        (With<DebugCursorTail<T>>, Without<DebugCursor<T>>),
    >,
    mut visibility_query: Query<&mut Visibility, With<DebugCursorMesh<T>>>,
    raycast_source_query: Query<&RayCastSource<T>>,
) {
    let cube_size = 0.04;
    let cube_tail_scale = 20.0;
    let ball_size = 0.08;
    let debug_material = &materials.add(StandardMaterial {
        base_color: Color::rgb(0.0, 1.0, 0.0),
        unlit: true,
        ..Default::default()
    });

    for _source in added_sources_query.iter() {
        commands
            // cursor
            .spawn_bundle(PbrBundle {
                mesh: meshes.add(Mesh::from(shape::Icosphere {
                    subdivisions: 4,
                    radius: ball_size,
                })),
                material: debug_material.clone(),
                ..Default::default()
            })
            .with_children(|parent| {
                let mut transform = Transform::from_translation(Vec3::new(
                    0.0,
                    (cube_size * cube_tail_scale) / 2.0,
                    0.0,
                ));
                transform.apply_non_uniform_scale(Vec3::from([1.0, cube_tail_scale, 1.0]));

                // child cube
                parent
                    .spawn_bundle(PbrBundle {
                        mesh: meshes.add(Mesh::from(shape::Cube { size: cube_size })),
                        material: debug_material.clone(),
                        transform,
                        ..Default::default()
                    })
                    .insert(DebugCursorTail::<T>::default())
                    .insert(DebugCursorMesh::<T>::default());
            })
            .insert(DebugCursor::<T>::default())
            .insert(DebugCursorMesh::<T>::default());
    }

    // Set the cursor translation to the top pick's world coordinates
    for raycast_source in raycast_source_query.iter() {
        match raycast_source.intersect_top() {
            Some(top_intersection) => {
                let transform_new = top_intersection.1.normal_ray().to_transform();
                for mut transform in cursor_query.iter_mut() {
                    *transform = GlobalTransform::from_matrix(transform_new);
                }
                for mut transform in cursor_tail_query.iter_mut() {
                    let scale = Vec3::from([1.0, cube_tail_scale, 1.0]);
                    let rotation = Quat::default();
                    let translation = Vec3::new(0.0, (cube_size * cube_tail_scale) / 2.0, 0.0);
                    let transform_move =
                        Mat4::from_scale_rotation_translation(scale, rotation, translation);
                    *transform = GlobalTransform::from_matrix(transform_new * transform_move)
                }
                for mut visible in &mut visibility_query.iter_mut() {
                    visible.is_visible = true;
                }
            }
            None => {
                for mut visible in &mut visibility_query.iter_mut() {
                    visible.is_visible = false;
                }
            }
        }
    }
}