pub mod box_widget;
pub mod cylinder;
pub mod disk;
pub mod line_probe;
pub mod plane;
pub mod polyline_widget;
pub mod sphere;
pub mod spline;
pub use box_widget::BoxWidget;
pub use cylinder::CylinderWidget;
pub use disk::DiskWidget;
pub use line_probe::LineProbeWidget;
pub use plane::PlaneWidget;
pub use polyline_widget::PolylineWidget;
pub use sphere::SphereWidget;
pub use spline::SplineWidget;
use crate::renderer::RenderCamera;
#[derive(Clone, Debug)]
pub struct WidgetContext {
pub camera: RenderCamera,
pub viewport_size: glam::Vec2,
pub cursor_viewport: glam::Vec2,
pub drag_started: bool,
pub dragging: bool,
pub released: bool,
pub double_clicked: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum WidgetResult {
None,
Updated,
}
pub(super) fn handle_world_radius(
pos: glam::Vec3,
camera: &RenderCamera,
viewport_height: f32,
target_px: f32,
) -> f32 {
let eye = glam::Vec3::from(camera.eye_position);
let dist = (pos - eye).length().max(0.001);
let world_per_px = 2.0 * (camera.fov * 0.5).tan() * dist / viewport_height.max(1.0);
world_per_px * target_px
}
pub(super) fn ctx_ray(ctx: &WidgetContext) -> (glam::Vec3, glam::Vec3) {
let vp = ctx.camera.projection * ctx.camera.view;
crate::interaction::picking::screen_to_ray(ctx.cursor_viewport, ctx.viewport_size, vp.inverse())
}
pub(super) fn ray_point_dist(
ray_origin: glam::Vec3,
ray_dir: glam::Vec3,
point: glam::Vec3,
) -> f32 {
let t = (point - ray_origin).dot(ray_dir).max(0.0);
(ray_origin + ray_dir * t - point).length()
}
pub(super) fn any_perpendicular(n: glam::Vec3) -> glam::Vec3 {
let len = n.length();
if len < 1e-6 { return glam::Vec3::X; }
let n = n / len;
if n.x.abs() < 0.9 {
n.cross(glam::Vec3::X).normalize()
} else {
n.cross(glam::Vec3::Y).normalize()
}
}
pub(super) fn any_perpendicular_pair(n: glam::Vec3) -> (glam::Vec3, glam::Vec3) {
let u = any_perpendicular(n);
let len = n.length();
let n_unit = if len > 1e-6 { n / len } else { glam::Vec3::Z };
let v = n_unit.cross(u);
(u, v)
}