diff options
Diffstat (limited to 'engine/src/ui/view/transform_3d.rs')
| -rw-r--r-- | engine/src/ui/view/transform_3d.rs | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/engine/src/ui/view/transform_3d.rs b/engine/src/ui/view/transform_3d.rs new file mode 100644 index 0000000..a426b2a --- /dev/null +++ b/engine/src/ui/view/transform_3d.rs @@ -0,0 +1,128 @@ +use dear_imguizmo::GuizmoExt; + +use crate::camera::{Active as ActiveCamera, Camera}; +use crate::data_types::dimens::Dimens3; +use crate::ecs::pair::ChildOf; +use crate::ecs::query::term::{Traverse, TraverseUp, With, Without}; +use crate::ecs::sole::Single; +use crate::ecs::Query; +use crate::projection::ClipVolume as ProjectionClipVolume; +use crate::scene::{Active as ActiveScene, Scene}; +use crate::transform::Transform; +use crate::ui::dear_imgui::{ + Context as DearImguiContext, + TargetWindow as DearImguiTargetWindow, +}; +use crate::vector::Vec3; +use crate::windowing::window::{Closed as WindowClosed, Window}; + +pub fn show( + subject_query: Query<( + &mut Transform, + Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>, + Without<ActiveCamera>, + )>, + camera_query: Query<( + &Camera, + &Transform, + Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>, + With<ActiveCamera>, + )>, + target_window_query: Query<( + &Window, + With<DearImguiTargetWindow>, + Without<WindowClosed>, + )>, + mut dear_imgui_context: Single<DearImguiContext>, +) -> Result<(), crate::Error> +{ + let dear_imgui_context = dear_imgui_context.get_mut()?; + + let Some(frame) = dear_imgui_context.frame() else { + return Ok(()); + }; + + let Some((camera, camera_world_pos)) = camera_query.iter().next() else { + return Ok(()); + }; + + let Some((target_window,)) = target_window_query.iter().next() else { + return Ok(()); + }; + + let gizmo = frame.guizmo(); + + let [display_width, display_height] = frame.io().display_size(); + + gizmo.set_rect(0.0, 0.0, display_width, display_height); + + // The widgets should appear under dear imgui windows + gizmo.set_drawlist_background(); + + let col_major_view = flatten_matrix( + camera + .to_view_matrix(camera_world_pos.position) + .to_column_major(), + ); + + let col_major_projection = flatten_matrix( + camera + .projection + .to_matrix_rh(target_window.inner_size, ProjectionClipVolume::NegOneToOne) + .to_column_major(), + ); + + for (subject_index, (mut subject_transform,)) in subject_query.iter().enumerate() { + let subject_index = match i32::try_from(subject_index) { + Ok(subject_index) => subject_index, + Err(err) => { + tracing::error!("Invalid subject index {subject_index}: {err}"); + break; + } + }; + + // No rotation + let rotation = [0.0, 0.0, 0.0]; + + let mut col_major_model_mat = dear_imguizmo::recompose_matrix( + &subject_transform.position.into(), + &rotation, + &subject_transform.scale.into(), + ); + + let _id_token = gizmo.push_id(subject_index); + + let used = gizmo + .manipulate_config( + &col_major_view, + &col_major_projection, + &mut col_major_model_mat, + ) + .operation( + dear_imguizmo::Operation::TRANSLATE | dear_imguizmo::Operation::SCALE, + ) + .mode(dear_imguizmo::Mode::World) + .build(); + + if used { + let (translation, _rotation, scale) = + dear_imguizmo::decompose_matrix(&col_major_model_mat); + + subject_transform.position = Vec3::from(translation); + subject_transform.scale = Dimens3::from(scale); + } + } + + Ok(()) +} + +fn flatten_matrix(mat: [[f32; 4]; 4]) -> [f32; 4 * 4] +{ + let flattened = mat.as_flattened(); + + let Some(flattened) = flattened.as_array::<{ 4 * 4 }>() else { + unreachable!(); + }; + + flattened.clone() +} |
