summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engine')
-rw-r--r--engine/Cargo.toml4
-rw-r--r--engine/src/ui/view.rs1
-rw-r--r--engine/src/ui/view/transform_3d.rs128
3 files changed, 133 insertions, 0 deletions
diff --git a/engine/Cargo.toml b/engine/Cargo.toml
index 322e6c3..f46433e 100644
--- a/engine/Cargo.toml
+++ b/engine/Cargo.toml
@@ -48,6 +48,10 @@ branch = "prebuilt-and-artifacts"
version = "=0.16.0-alpha.1"
features = ["freetype"]
+[dependencies.dear-imguizmo]
+version = "=0.16.0-alpha.1"
+default-features = false # A dependency on glam is not desired
+
[build-dependencies]
build-rs = "0.3.4"
serde = { version = "1.0.228", features = ["derive"] }
diff --git a/engine/src/ui/view.rs b/engine/src/ui/view.rs
index ed714d6..42601a3 100644
--- a/engine/src/ui/view.rs
+++ b/engine/src/ui/view.rs
@@ -1 +1,2 @@
+pub mod transform_3d;
pub mod world;
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()
+}