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
128
129
use crate::{PluginState, RayCastSource};
use bevy::prelude::*;
use std::marker::PhantomData;

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

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

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,
    state: Res<PluginState<T>>,
    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 Visible, With<DebugCursorMesh<T>>>,
    raycast_source_query: Query<&RayCastSource<T>>,
) {
    if !state.enabled {
        return;
    }

    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;
                }
            }
        }
    }
}