use crate::ecs::generational_registry::registry_entry_by_name_mut;
use crate::ecs::material::resources::material_registry_insert;
use crate::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum GizmoMode {
#[default]
LocalTranslation,
GlobalTranslation,
Rotation,
Scale,
}
pub struct GizmoState {
pub root: Entity,
pub target: Entity,
pub mode: GizmoMode,
pub axis_entities: GizmoAxisEntities,
}
#[derive(Debug, Clone, Default)]
pub struct GizmoAxisEntities {
pub x_axis: Option<Entity>,
pub y_axis: Option<Entity>,
pub z_axis: Option<Entity>,
pub center_cube: Option<Entity>,
pub xy_plane: Option<Entity>,
pub yz_plane: Option<Entity>,
pub xz_plane: Option<Entity>,
pub x_axis_line: Option<Entity>,
pub y_axis_line: Option<Entity>,
pub z_axis_line: Option<Entity>,
}
#[derive(Debug, Clone, Copy)]
pub struct GizmoConfig {
pub arrow_length: f32,
pub arrow_radius: f32,
pub cone_height: f32,
pub cone_radius: f32,
pub highlight_factor: f32,
pub normal_factor: f32,
pub scale_factor: f32,
pub min_scale: f32,
pub max_scale: f32,
}
impl Default for GizmoConfig {
fn default() -> Self {
Self {
arrow_length: 2.0,
arrow_radius: 0.06,
cone_height: 0.5,
cone_radius: 0.15,
highlight_factor: 1.0,
normal_factor: 1.0,
scale_factor: 0.08,
min_scale: 0.3,
max_scale: 50.0,
}
}
}
fn set_gizmo_layer(world: &mut World, entity: Entity) {
if let Some(render_layer) = world.get_render_layer_mut(entity) {
render_layer.0 = RenderLayer::OVERLAY;
}
}
struct AxisArrowParams {
parent: Entity,
direction: Vec3,
color: Vec3,
length: f32,
cylinder_radius: f32,
cone_height: f32,
cone_radius: f32,
axis_name: String,
}
struct AxisWithCubeParams {
parent: Entity,
direction: Vec3,
color: Vec3,
length: f32,
cylinder_radius: f32,
cube_size: f32,
axis_name: String,
}
struct RotationRingParams {
parent: Entity,
axis: Vec3,
color: Vec3,
ring_radius: f32,
axis_name: String,
}
pub fn create_translation_gizmo(
world: &mut World,
target_entity: Entity,
mode: GizmoMode,
) -> GizmoState {
let config = GizmoConfig::default();
let gizmo_root = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| NAME
| VISIBILITY
| RENDER_LAYER,
1,
)[0];
let name_str = match mode {
GizmoMode::LocalTranslation => "Local Translation Gizmo",
GizmoMode::GlobalTranslation => "Global Translation Gizmo",
_ => "Translation Gizmo",
};
if let Some(name) = world.get_name_mut(gizmo_root) {
name.0 = name_str.to_string();
}
if let Some(transform) = world.get_local_transform(gizmo_root) {
let mut new_transform = *transform;
new_transform.translation = Vec3::zeros();
new_transform.scale = nalgebra_glm::vec3(1.0, 1.0, 1.0);
world.assign_local_transform(gizmo_root, new_transform);
}
let mut axis_entities = GizmoAxisEntities::default();
let arrow_length = config.arrow_length;
let arrow_radius = config.arrow_radius;
let cone_height = config.cone_height;
let cone_radius = config.cone_radius;
axis_entities.x_axis = Some(create_axis_arrow(
world,
AxisArrowParams {
parent: gizmo_root,
direction: nalgebra_glm::vec3(1.0, 0.0, 0.0),
color: nalgebra_glm::vec3(0.7, 0.0, 0.0),
length: arrow_length,
cylinder_radius: arrow_radius,
cone_height,
cone_radius,
axis_name: "X Axis".to_string(),
},
));
axis_entities.y_axis = Some(create_axis_arrow(
world,
AxisArrowParams {
parent: gizmo_root,
direction: nalgebra_glm::vec3(0.0, 1.0, 0.0),
color: nalgebra_glm::vec3(0.0, 0.7, 0.0),
length: arrow_length,
cylinder_radius: arrow_radius,
cone_height,
cone_radius,
axis_name: "Y Axis".to_string(),
},
));
axis_entities.z_axis = Some(create_axis_arrow(
world,
AxisArrowParams {
parent: gizmo_root,
direction: nalgebra_glm::vec3(0.0, 0.0, 1.0),
color: nalgebra_glm::vec3(0.0, 0.0, 0.7),
length: arrow_length,
cylinder_radius: arrow_radius,
cone_height,
cone_radius,
axis_name: "Z Axis".to_string(),
},
));
let center_cube = create_center_cube(world, gizmo_root);
axis_entities.center_cube = Some(center_cube);
axis_entities.xy_plane = Some(create_plane_cube(
world,
gizmo_root,
nalgebra_glm::vec3(0.0, 0.0, 1.0),
nalgebra_glm::vec3(0.4, 0.4, 0.0),
arrow_length * 0.3,
"XY Plane",
));
axis_entities.yz_plane = Some(create_plane_cube(
world,
gizmo_root,
nalgebra_glm::vec3(1.0, 0.0, 0.0),
nalgebra_glm::vec3(0.0, 0.4, 0.4),
arrow_length * 0.3,
"YZ Plane",
));
axis_entities.xz_plane = Some(create_plane_cube(
world,
gizmo_root,
nalgebra_glm::vec3(0.0, 1.0, 0.0),
nalgebra_glm::vec3(0.4, 0.0, 0.4),
arrow_length * 0.3,
"XZ Plane",
));
axis_entities.x_axis_line = Some(create_infinite_axis_line(
world,
gizmo_root,
nalgebra_glm::vec3(1.0, 0.0, 0.0),
nalgebra_glm::vec3(0.7, 0.0, 0.0),
"X Axis Line",
));
axis_entities.y_axis_line = Some(create_infinite_axis_line(
world,
gizmo_root,
nalgebra_glm::vec3(0.0, 1.0, 0.0),
nalgebra_glm::vec3(0.0, 0.7, 0.0),
"Y Axis Line",
));
axis_entities.z_axis_line = Some(create_infinite_axis_line(
world,
gizmo_root,
nalgebra_glm::vec3(0.0, 0.0, 1.0),
nalgebra_glm::vec3(0.0, 0.0, 0.7),
"Z Axis Line",
));
GizmoState {
root: gizmo_root,
target: target_entity,
mode,
axis_entities,
}
}
pub fn create_scale_gizmo(world: &mut World, target_entity: Entity) -> GizmoState {
let config = GizmoConfig::default();
let gizmo_root = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| NAME
| VISIBILITY
| RENDER_LAYER,
1,
)[0];
if let Some(name) = world.get_name_mut(gizmo_root) {
name.0 = "Scale Gizmo".to_string();
}
if let Some(transform) = world.get_local_transform(gizmo_root) {
let mut new_transform = *transform;
new_transform.translation = Vec3::zeros();
new_transform.scale = nalgebra_glm::vec3(1.0, 1.0, 1.0);
world.assign_local_transform(gizmo_root, new_transform);
}
let mut axis_entities = GizmoAxisEntities::default();
let arrow_length = config.arrow_length;
let arrow_radius = config.arrow_radius;
let cube_size = config.cone_height * 0.5;
axis_entities.x_axis = Some(create_axis_with_cube(
world,
AxisWithCubeParams {
parent: gizmo_root,
direction: nalgebra_glm::vec3(1.0, 0.0, 0.0),
color: nalgebra_glm::vec3(0.7, 0.0, 0.0),
length: arrow_length,
cylinder_radius: arrow_radius,
cube_size,
axis_name: "X Axis".to_string(),
},
));
axis_entities.y_axis = Some(create_axis_with_cube(
world,
AxisWithCubeParams {
parent: gizmo_root,
direction: nalgebra_glm::vec3(0.0, 1.0, 0.0),
color: nalgebra_glm::vec3(0.0, 0.7, 0.0),
length: arrow_length,
cylinder_radius: arrow_radius,
cube_size,
axis_name: "Y Axis".to_string(),
},
));
axis_entities.z_axis = Some(create_axis_with_cube(
world,
AxisWithCubeParams {
parent: gizmo_root,
direction: nalgebra_glm::vec3(0.0, 0.0, 1.0),
color: nalgebra_glm::vec3(0.0, 0.0, 0.7),
length: arrow_length,
cylinder_radius: arrow_radius,
cube_size,
axis_name: "Z Axis".to_string(),
},
));
let center_cube = create_center_cube(world, gizmo_root);
axis_entities.center_cube = Some(center_cube);
axis_entities.xy_plane = Some(create_plane_cube(
world,
gizmo_root,
nalgebra_glm::vec3(0.0, 0.0, 1.0),
nalgebra_glm::vec3(0.4, 0.4, 0.0),
arrow_length * 0.3,
"XY Plane",
));
axis_entities.yz_plane = Some(create_plane_cube(
world,
gizmo_root,
nalgebra_glm::vec3(1.0, 0.0, 0.0),
nalgebra_glm::vec3(0.0, 0.4, 0.4),
arrow_length * 0.3,
"YZ Plane",
));
axis_entities.xz_plane = Some(create_plane_cube(
world,
gizmo_root,
nalgebra_glm::vec3(0.0, 1.0, 0.0),
nalgebra_glm::vec3(0.4, 0.0, 0.4),
arrow_length * 0.3,
"XZ Plane",
));
axis_entities.x_axis_line = Some(create_infinite_axis_line(
world,
gizmo_root,
nalgebra_glm::vec3(1.0, 0.0, 0.0),
nalgebra_glm::vec3(0.7, 0.0, 0.0),
"X Axis Line",
));
axis_entities.y_axis_line = Some(create_infinite_axis_line(
world,
gizmo_root,
nalgebra_glm::vec3(0.0, 1.0, 0.0),
nalgebra_glm::vec3(0.0, 0.7, 0.0),
"Y Axis Line",
));
axis_entities.z_axis_line = Some(create_infinite_axis_line(
world,
gizmo_root,
nalgebra_glm::vec3(0.0, 0.0, 1.0),
nalgebra_glm::vec3(0.0, 0.0, 0.7),
"Z Axis Line",
));
GizmoState {
root: gizmo_root,
target: target_entity,
mode: GizmoMode::Scale,
axis_entities,
}
}
pub fn create_rotation_gizmo(world: &mut World, target_entity: Entity) -> GizmoState {
let gizmo_root = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| NAME
| VISIBILITY
| RENDER_LAYER,
1,
)[0];
if let Some(name) = world.get_name_mut(gizmo_root) {
name.0 = "Rotation Gizmo".to_string();
}
set_gizmo_layer(world, gizmo_root);
if let Some(transform) = world.get_local_transform(gizmo_root) {
let mut new_transform = *transform;
new_transform.translation = Vec3::zeros();
new_transform.rotation = Quat::identity();
new_transform.scale = nalgebra_glm::vec3(1.0, 1.0, 1.0);
world.assign_local_transform(gizmo_root, new_transform);
}
if let Some(visibility) = world.get_visibility_mut(gizmo_root) {
visibility.visible = true;
}
let ring_radius = 2.0;
let axis_entities = GizmoAxisEntities {
x_axis: Some(create_rotation_ring(
world,
RotationRingParams {
parent: gizmo_root,
axis: nalgebra_glm::vec3(1.0, 0.0, 0.0),
color: nalgebra_glm::vec3(0.9, 0.2, 0.2),
ring_radius,
axis_name: "X Rotation Ring".to_string(),
},
)),
y_axis: Some(create_rotation_ring(
world,
RotationRingParams {
parent: gizmo_root,
axis: nalgebra_glm::vec3(0.0, 1.0, 0.0),
color: nalgebra_glm::vec3(0.2, 0.9, 0.2),
ring_radius,
axis_name: "Y Rotation Ring".to_string(),
},
)),
z_axis: Some(create_rotation_ring(
world,
RotationRingParams {
parent: gizmo_root,
axis: nalgebra_glm::vec3(0.0, 0.0, 1.0),
color: nalgebra_glm::vec3(0.2, 0.2, 0.9),
ring_radius,
axis_name: "Z Rotation Ring".to_string(),
},
)),
x_axis_line: Some(create_infinite_axis_line(
world,
gizmo_root,
nalgebra_glm::vec3(1.0, 0.0, 0.0),
nalgebra_glm::vec3(0.9, 0.2, 0.2),
"X Axis Line",
)),
y_axis_line: Some(create_infinite_axis_line(
world,
gizmo_root,
nalgebra_glm::vec3(0.0, 1.0, 0.0),
nalgebra_glm::vec3(0.2, 0.9, 0.2),
"Y Axis Line",
)),
z_axis_line: Some(create_infinite_axis_line(
world,
gizmo_root,
nalgebra_glm::vec3(0.0, 0.0, 1.0),
nalgebra_glm::vec3(0.2, 0.2, 0.9),
"Z Axis Line",
)),
..Default::default()
};
GizmoState {
root: gizmo_root,
target: target_entity,
mode: GizmoMode::Rotation,
axis_entities,
}
}
fn create_axis_arrow(world: &mut World, params: AxisArrowParams) -> Entity {
let axis_group = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| PARENT
| NAME
| VISIBILITY
| RENDER_LAYER
| BOUNDING_VOLUME,
1,
)[0];
if let Some(name) = world.get_name_mut(axis_group) {
name.0 = params.axis_name.clone();
}
world.update_parent(axis_group, Some(Parent(Some(params.parent))));
if let Some(transform) = world.get_local_transform(axis_group) {
let mut new_transform = *transform;
new_transform.translation = Vec3::zeros();
new_transform.rotation = Quat::identity();
new_transform.scale = nalgebra_glm::vec3(1.0, 1.0, 1.0);
world.assign_local_transform(axis_group, new_transform);
}
if let Some(visibility) = world.get_visibility_mut(axis_group) {
visibility.visible = true;
}
set_gizmo_layer(world, axis_group);
let rotation = if params.direction.y.abs() > 0.99 {
Quat::identity()
} else if params.direction.x.abs() > 0.99 {
nalgebra_glm::quat_angle_axis(
if params.direction.x > 0.0 {
-std::f32::consts::PI / 2.0
} else {
std::f32::consts::PI / 2.0
},
&nalgebra_glm::vec3(0.0, 0.0, 1.0),
)
} else if params.direction.z.abs() > 0.99 {
nalgebra_glm::quat_angle_axis(
if params.direction.z > 0.0 {
std::f32::consts::PI / 2.0
} else {
-std::f32::consts::PI / 2.0
},
&nalgebra_glm::vec3(1.0, 0.0, 0.0),
)
} else {
Quat::identity()
};
let cylinder_entity = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| RENDER_MESH
| MATERIAL_REF
| VISIBILITY
| PARENT
| NAME
| RENDER_LAYER,
1,
)[0];
world
.resources
.mesh_render_state
.mark_entity_added(cylinder_entity);
if let Some(name) = world.get_name_mut(cylinder_entity) {
name.0 = format!("{} Cylinder", params.axis_name);
}
set_gizmo_layer(world, cylinder_entity);
world.update_parent(cylinder_entity, Some(Parent(Some(axis_group))));
if let Some(transform) = world.get_local_transform(cylinder_entity) {
let mut new_transform = *transform;
new_transform.translation = params.direction * (params.length * 0.5);
new_transform.rotation = rotation;
new_transform.scale = nalgebra_glm::vec3(
params.cylinder_radius / 0.5,
params.length / 1.0,
params.cylinder_radius / 0.5,
);
world.assign_local_transform(cylinder_entity, new_transform);
}
if let Some(mesh) = world.get_render_mesh_mut(cylinder_entity) {
mesh.name = "Cylinder".to_string();
}
let cylinder_material_name = format!("Gizmo_{}_Cylinder", cylinder_entity.id);
material_registry_insert(
&mut world.resources.material_registry,
cylinder_material_name.clone(),
Material {
base_color: [params.color.x, params.color.y, params.color.z, 1.0],
unlit: true,
alpha_mode: AlphaMode::Opaque,
..Default::default()
},
);
if let Some(&index) = world
.resources
.material_registry
.registry
.name_to_index
.get(&cylinder_material_name)
{
world
.resources
.material_registry
.registry
.add_reference(index);
}
world.set_material_ref(cylinder_entity, MaterialRef::new(cylinder_material_name));
let cone_entity = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| RENDER_MESH
| MATERIAL_REF
| VISIBILITY
| PARENT
| NAME
| RENDER_LAYER,
1,
)[0];
world
.resources
.mesh_render_state
.mark_entity_added(cone_entity);
if let Some(name) = world.get_name_mut(cone_entity) {
name.0 = format!("{} Cone", params.axis_name);
}
set_gizmo_layer(world, cone_entity);
world.update_parent(cone_entity, Some(Parent(Some(axis_group))));
if let Some(transform) = world.get_local_transform(cone_entity) {
let mut new_transform = *transform;
let cone_scale_radius = 3.0;
let cone_scale_height = 2.0;
let scaled_cone_height = params.cone_height * cone_scale_height;
new_transform.translation = params.direction * (params.length + scaled_cone_height / 4.0);
new_transform.rotation = rotation;
new_transform.scale = nalgebra_glm::vec3(
params.cone_radius / 1.0 * cone_scale_radius,
params.cone_height / 2.0 * cone_scale_height,
params.cone_radius / 1.0 * cone_scale_radius,
);
world.assign_local_transform(cone_entity, new_transform);
}
if let Some(mesh) = world.get_render_mesh_mut(cone_entity) {
mesh.name = "Cone".to_string();
}
let cone_material_name = format!("Gizmo_{}_Cone", cone_entity.id);
material_registry_insert(
&mut world.resources.material_registry,
cone_material_name.clone(),
Material {
base_color: [params.color.x, params.color.y, params.color.z, 1.0],
unlit: true,
alpha_mode: AlphaMode::Opaque,
..Default::default()
},
);
if let Some(&index) = world
.resources
.material_registry
.registry
.name_to_index
.get(&cone_material_name)
{
world
.resources
.material_registry
.registry
.add_reference(index);
}
world.set_material_ref(cone_entity, MaterialRef::new(cone_material_name));
if let Some(bounding) = world.get_bounding_volume_mut(axis_group) {
let total_length = params.length + params.cone_height;
let click_radius = 0.15;
let center = params.direction * (total_length * 0.5);
bounding.obb.center = center;
if params.direction.y.abs() > 0.99 {
bounding.obb.half_extents =
nalgebra_glm::vec3(click_radius, total_length * 0.5, click_radius);
bounding.obb.orientation = Quat::identity();
} else if params.direction.x.abs() > 0.99 {
bounding.obb.half_extents =
nalgebra_glm::vec3(total_length * 0.5, click_radius, click_radius);
bounding.obb.orientation = Quat::identity();
} else if params.direction.z.abs() > 0.99 {
bounding.obb.half_extents =
nalgebra_glm::vec3(click_radius, click_radius, total_length * 0.5);
bounding.obb.orientation = Quat::identity();
}
bounding.sphere_radius =
(click_radius * click_radius + (total_length * 0.5) * (total_length * 0.5)).sqrt();
}
axis_group
}
fn create_center_cube(world: &mut World, parent: Entity) -> Entity {
let center_cube = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| RENDER_MESH
| MATERIAL_REF
| VISIBILITY
| PARENT
| NAME
| RENDER_LAYER
| BOUNDING_VOLUME,
1,
)[0];
world
.resources
.mesh_render_state
.mark_entity_added(center_cube);
if let Some(name) = world.get_name_mut(center_cube) {
name.0 = "Center Cube".to_string();
}
set_gizmo_layer(world, center_cube);
world.update_parent(center_cube, Some(Parent(Some(parent))));
if let Some(transform) = world.get_local_transform(center_cube) {
let mut new_transform = *transform;
new_transform.translation = Vec3::zeros();
new_transform.rotation = Quat::identity();
new_transform.scale = nalgebra_glm::vec3(0.15, 0.15, 0.15);
world.assign_local_transform(center_cube, new_transform);
}
if let Some(mesh) = world.get_render_mesh_mut(center_cube) {
mesh.name = "Cube".to_string();
}
let material_name = format!("Gizmo_{}_CenterCube", center_cube.id);
material_registry_insert(
&mut world.resources.material_registry,
material_name.clone(),
Material {
base_color: [0.6, 0.6, 0.6, 1.0],
unlit: true,
alpha_mode: AlphaMode::Opaque,
..Default::default()
},
);
if let Some(&index) = world
.resources
.material_registry
.registry
.name_to_index
.get(&material_name)
{
world
.resources
.material_registry
.registry
.add_reference(index);
}
world.set_material_ref(center_cube, MaterialRef::new(material_name));
if let Some(visibility) = world.get_visibility_mut(center_cube) {
visibility.visible = true;
}
if let Some(bounding) = world.get_bounding_volume_mut(center_cube) {
let click_size = 0.25;
bounding.sphere_radius = click_size * 0.866;
bounding.obb.center = Vec3::zeros();
bounding.obb.half_extents =
nalgebra_glm::vec3(click_size * 0.5, click_size * 0.5, click_size * 0.5);
bounding.obb.orientation = Quat::identity();
}
center_cube
}
fn create_axis_with_cube(world: &mut World, params: AxisWithCubeParams) -> Entity {
let axis_group = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| PARENT
| NAME
| VISIBILITY
| RENDER_LAYER
| BOUNDING_VOLUME,
1,
)[0];
if let Some(name) = world.get_name_mut(axis_group) {
name.0 = params.axis_name.clone();
}
world.update_parent(axis_group, Some(Parent(Some(params.parent))));
if let Some(transform) = world.get_local_transform(axis_group) {
let mut new_transform = *transform;
new_transform.translation = Vec3::zeros();
new_transform.rotation = Quat::identity();
new_transform.scale = nalgebra_glm::vec3(1.0, 1.0, 1.0);
world.assign_local_transform(axis_group, new_transform);
}
if let Some(visibility) = world.get_visibility_mut(axis_group) {
visibility.visible = true;
}
set_gizmo_layer(world, axis_group);
let rotation = if params.direction.y.abs() > 0.99 {
Quat::identity()
} else if params.direction.x.abs() > 0.99 {
nalgebra_glm::quat_angle_axis(
if params.direction.x > 0.0 {
-std::f32::consts::PI / 2.0
} else {
std::f32::consts::PI / 2.0
},
&nalgebra_glm::vec3(0.0, 0.0, 1.0),
)
} else if params.direction.z.abs() > 0.99 {
nalgebra_glm::quat_angle_axis(
if params.direction.z > 0.0 {
std::f32::consts::PI / 2.0
} else {
-std::f32::consts::PI / 2.0
},
&nalgebra_glm::vec3(1.0, 0.0, 0.0),
)
} else {
Quat::identity()
};
let cylinder_entity = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| RENDER_MESH
| MATERIAL_REF
| VISIBILITY
| PARENT
| NAME
| RENDER_LAYER,
1,
)[0];
world
.resources
.mesh_render_state
.mark_entity_added(cylinder_entity);
if let Some(name) = world.get_name_mut(cylinder_entity) {
name.0 = format!("{} Cylinder", params.axis_name);
}
set_gizmo_layer(world, cylinder_entity);
world.update_parent(cylinder_entity, Some(Parent(Some(axis_group))));
if let Some(transform) = world.get_local_transform(cylinder_entity) {
let mut new_transform = *transform;
new_transform.translation = params.direction * (params.length * 0.5);
new_transform.rotation = rotation;
new_transform.scale = nalgebra_glm::vec3(
params.cylinder_radius / 0.5,
params.length / 1.0,
params.cylinder_radius / 0.5,
);
world.assign_local_transform(cylinder_entity, new_transform);
}
if let Some(mesh) = world.get_render_mesh_mut(cylinder_entity) {
mesh.name = "Cylinder".to_string();
}
let cylinder_material_name = format!("Gizmo_{}_ScaleCylinder", cylinder_entity.id);
material_registry_insert(
&mut world.resources.material_registry,
cylinder_material_name.clone(),
Material {
base_color: [params.color.x, params.color.y, params.color.z, 1.0],
unlit: true,
alpha_mode: AlphaMode::Opaque,
..Default::default()
},
);
if let Some(&index) = world
.resources
.material_registry
.registry
.name_to_index
.get(&cylinder_material_name)
{
world
.resources
.material_registry
.registry
.add_reference(index);
}
world.set_material_ref(cylinder_entity, MaterialRef::new(cylinder_material_name));
let cube_entity = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| RENDER_MESH
| MATERIAL_REF
| VISIBILITY
| PARENT
| NAME
| RENDER_LAYER,
1,
)[0];
world
.resources
.mesh_render_state
.mark_entity_added(cube_entity);
if let Some(name) = world.get_name_mut(cube_entity) {
name.0 = format!("{} Cube", params.axis_name);
}
set_gizmo_layer(world, cube_entity);
world.update_parent(cube_entity, Some(Parent(Some(axis_group))));
if let Some(transform) = world.get_local_transform(cube_entity) {
let mut new_transform = *transform;
new_transform.translation = params.direction * params.length;
new_transform.rotation = Quat::identity();
new_transform.scale =
nalgebra_glm::vec3(params.cube_size, params.cube_size, params.cube_size);
world.assign_local_transform(cube_entity, new_transform);
}
if let Some(mesh) = world.get_render_mesh_mut(cube_entity) {
mesh.name = "Cube".to_string();
}
let cube_material_name = format!("Gizmo_{}_ScaleCube", cube_entity.id);
material_registry_insert(
&mut world.resources.material_registry,
cube_material_name.clone(),
Material {
base_color: [params.color.x, params.color.y, params.color.z, 1.0],
unlit: true,
alpha_mode: AlphaMode::Opaque,
..Default::default()
},
);
if let Some(&index) = world
.resources
.material_registry
.registry
.name_to_index
.get(&cube_material_name)
{
world
.resources
.material_registry
.registry
.add_reference(index);
}
world.set_material_ref(cube_entity, MaterialRef::new(cube_material_name));
if let Some(bounding) = world.get_bounding_volume_mut(axis_group) {
let total_length = params.length + params.cube_size * 0.5;
let click_radius = 0.15;
let center = params.direction * (total_length * 0.5);
bounding.obb.center = center;
if params.direction.y.abs() > 0.99 {
bounding.obb.half_extents =
nalgebra_glm::vec3(click_radius, total_length * 0.5, click_radius);
bounding.obb.orientation = Quat::identity();
} else if params.direction.x.abs() > 0.99 {
bounding.obb.half_extents =
nalgebra_glm::vec3(total_length * 0.5, click_radius, click_radius);
bounding.obb.orientation = Quat::identity();
} else if params.direction.z.abs() > 0.99 {
bounding.obb.half_extents =
nalgebra_glm::vec3(click_radius, click_radius, total_length * 0.5);
bounding.obb.orientation = Quat::identity();
}
bounding.sphere_radius =
(click_radius * click_radius + (total_length * 0.5) * (total_length * 0.5)).sqrt();
}
axis_group
}
fn create_rotation_ring(world: &mut World, params: RotationRingParams) -> Entity {
let ring_entity = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| PARENT
| NAME
| VISIBILITY
| RENDER_LAYER
| BOUNDING_VOLUME
| LINES,
1,
)[0];
if let Some(name) = world.get_name_mut(ring_entity) {
name.0 = params.axis_name.clone();
}
world.update_parent(ring_entity, Some(Parent(Some(params.parent))));
if let Some(transform) = world.get_local_transform(ring_entity) {
let mut new_transform = *transform;
new_transform.translation = Vec3::zeros();
new_transform.rotation = Quat::identity();
new_transform.scale = nalgebra_glm::vec3(1.0, 1.0, 1.0);
world.assign_local_transform(ring_entity, new_transform);
}
if let Some(visibility) = world.get_visibility_mut(ring_entity) {
visibility.visible = true;
}
set_gizmo_layer(world, ring_entity);
let segments = 64;
let color = nalgebra_glm::vec4(params.color.x, params.color.y, params.color.z, 1.0);
if let Some(lines) = world.get_lines_mut(ring_entity) {
lines.lines.clear();
for segment_index in 0..segments {
let angle1 = 2.0 * std::f32::consts::PI * (segment_index as f32) / (segments as f32);
let angle2 =
2.0 * std::f32::consts::PI * ((segment_index + 1) as f32) / (segments as f32);
let (start, end) = if params.axis.x.abs() > 0.99 {
(
nalgebra_glm::vec3(
0.0,
angle1.cos() * params.ring_radius,
angle1.sin() * params.ring_radius,
),
nalgebra_glm::vec3(
0.0,
angle2.cos() * params.ring_radius,
angle2.sin() * params.ring_radius,
),
)
} else if params.axis.z.abs() > 0.99 {
(
nalgebra_glm::vec3(
angle1.cos() * params.ring_radius,
angle1.sin() * params.ring_radius,
0.0,
),
nalgebra_glm::vec3(
angle2.cos() * params.ring_radius,
angle2.sin() * params.ring_radius,
0.0,
),
)
} else {
(
nalgebra_glm::vec3(
angle1.cos() * params.ring_radius,
0.0,
angle1.sin() * params.ring_radius,
),
nalgebra_glm::vec3(
angle2.cos() * params.ring_radius,
0.0,
angle2.sin() * params.ring_radius,
),
)
};
lines.lines.push(Line { start, end, color });
}
lines.mark_dirty();
}
if let Some(bounding) = world.get_bounding_volume_mut(ring_entity) {
bounding.sphere_radius = params.ring_radius;
bounding.obb.center = Vec3::zeros();
let hit_thickness = 0.15;
if params.axis.x.abs() > 0.99 {
bounding.obb.half_extents =
nalgebra_glm::vec3(hit_thickness, params.ring_radius, params.ring_radius);
} else if params.axis.z.abs() > 0.99 {
bounding.obb.half_extents =
nalgebra_glm::vec3(params.ring_radius, params.ring_radius, hit_thickness);
} else {
bounding.obb.half_extents =
nalgebra_glm::vec3(params.ring_radius, hit_thickness, params.ring_radius);
}
bounding.obb.orientation = Quat::identity();
}
ring_entity
}
fn create_plane_cube(
world: &mut World,
parent: Entity,
plane_normal: Vec3,
color: Vec3,
size: f32,
plane_name: &str,
) -> Entity {
let plane_entity = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| RENDER_MESH
| MATERIAL_REF
| VISIBILITY
| PARENT
| NAME
| RENDER_LAYER
| BOUNDING_VOLUME,
1,
)[0];
world
.resources
.mesh_render_state
.mark_entity_added(plane_entity);
if let Some(name) = world.get_name_mut(plane_entity) {
name.0 = plane_name.to_string();
}
set_gizmo_layer(world, plane_entity);
world.update_parent(plane_entity, Some(Parent(Some(parent))));
if let Some(transform) = world.get_local_transform(plane_entity) {
let mut new_transform = *transform;
let offset = size * 0.5;
if plane_normal.z.abs() > 0.5 {
new_transform.translation = nalgebra_glm::vec3(offset, offset, 0.0);
new_transform.rotation = Quat::identity();
new_transform.scale = nalgebra_glm::vec3(size, size, size * 0.05);
} else if plane_normal.x.abs() > 0.5 {
new_transform.translation = nalgebra_glm::vec3(0.0, offset, offset);
new_transform.rotation = Quat::identity();
new_transform.scale = nalgebra_glm::vec3(size * 0.05, size, size);
} else {
new_transform.translation = nalgebra_glm::vec3(offset, 0.0, offset);
new_transform.rotation = Quat::identity();
new_transform.scale = nalgebra_glm::vec3(size, size * 0.05, size);
}
world.assign_local_transform(plane_entity, new_transform);
}
if let Some(mesh) = world.get_render_mesh_mut(plane_entity) {
mesh.name = "Cube".to_string();
}
let material_name = format!("Gizmo_{}_Plane", plane_entity.id);
material_registry_insert(
&mut world.resources.material_registry,
material_name.clone(),
Material {
base_color: [color.x, color.y, color.z, 0.4],
unlit: true,
alpha_mode: AlphaMode::Blend,
..Default::default()
},
);
if let Some(&index) = world
.resources
.material_registry
.registry
.name_to_index
.get(&material_name)
{
world
.resources
.material_registry
.registry
.add_reference(index);
}
world.set_material_ref(plane_entity, MaterialRef::new(material_name));
if let Some(visibility) = world.get_visibility_mut(plane_entity) {
visibility.visible = true;
}
if let Some(bounding) = world.get_bounding_volume_mut(plane_entity) {
let click_size = size * 1.2;
let thickness = 0.3;
bounding.sphere_radius = click_size * 0.866;
if plane_normal.z.abs() > 0.5 {
bounding.obb.center = Vec3::zeros();
bounding.obb.half_extents =
nalgebra_glm::vec3(click_size * 0.5, click_size * 0.5, thickness);
bounding.obb.orientation = Quat::identity();
} else if plane_normal.x.abs() > 0.5 {
bounding.obb.center = Vec3::zeros();
bounding.obb.half_extents =
nalgebra_glm::vec3(thickness, click_size * 0.5, click_size * 0.5);
bounding.obb.orientation = Quat::identity();
} else {
bounding.obb.center = Vec3::zeros();
bounding.obb.half_extents =
nalgebra_glm::vec3(click_size * 0.5, thickness, click_size * 0.5);
bounding.obb.orientation = Quat::identity();
}
}
plane_entity
}
fn create_infinite_axis_line(
world: &mut World,
parent: Entity,
direction: Vec3,
color: Vec3,
line_name: &str,
) -> Entity {
let line_entity = world.spawn_entities(
LOCAL_TRANSFORM
| LOCAL_TRANSFORM_DIRTY
| GLOBAL_TRANSFORM
| RENDER_MESH
| MATERIAL_REF
| PARENT
| NAME
| RENDER_LAYER
| VISIBILITY,
1,
)[0];
world
.resources
.mesh_render_state
.mark_entity_added(line_entity);
if let Some(name) = world.get_name_mut(line_entity) {
name.0 = line_name.to_string();
}
set_gizmo_layer(world, line_entity);
world.update_parent(line_entity, Some(Parent(Some(parent))));
let length = 2000.0;
let radius = 0.02;
let rotation = if direction.y.abs() > 0.99 {
Quat::identity()
} else if direction.x.abs() > 0.99 {
nalgebra_glm::quat_angle_axis(
if direction.x > 0.0 {
-std::f32::consts::PI / 2.0
} else {
std::f32::consts::PI / 2.0
},
&nalgebra_glm::vec3(0.0, 0.0, 1.0),
)
} else if direction.z.abs() > 0.99 {
nalgebra_glm::quat_angle_axis(
if direction.z > 0.0 {
std::f32::consts::PI / 2.0
} else {
-std::f32::consts::PI / 2.0
},
&nalgebra_glm::vec3(1.0, 0.0, 0.0),
)
} else {
Quat::identity()
};
if let Some(transform) = world.get_local_transform(line_entity) {
let mut new_transform = *transform;
new_transform.translation = Vec3::zeros();
new_transform.rotation = rotation;
new_transform.scale = nalgebra_glm::vec3(radius / 0.5, length / 1.0, radius / 0.5);
world.assign_local_transform(line_entity, new_transform);
}
if let Some(mesh) = world.get_render_mesh_mut(line_entity) {
mesh.name = "Cylinder".to_string();
}
let material_name = format!("Gizmo_{}_AxisLine", line_entity.id);
material_registry_insert(
&mut world.resources.material_registry,
material_name.clone(),
Material {
base_color: [color.x, color.y, color.z, 0.5],
unlit: true,
alpha_mode: AlphaMode::Blend,
..Default::default()
},
);
if let Some(&index) = world
.resources
.material_registry
.registry
.name_to_index
.get(&material_name)
{
world
.resources
.material_registry
.registry
.add_reference(index);
}
world.set_material_ref(line_entity, MaterialRef::new(material_name));
if let Some(visibility) = world.get_visibility_mut(line_entity) {
visibility.visible = false;
}
line_entity
}
pub fn destroy_gizmo(world: &mut World, gizmo: &GizmoState) {
let descendants = crate::ecs::transform::queries::query_descendants(world, gizmo.root);
let all_entities: Vec<Entity> = std::iter::once(gizmo.root)
.chain(descendants.iter().copied())
.collect();
for &entity in &all_entities {
if world.entity_has_components(entity, crate::ecs::world::RENDER_MESH) {
if let Some(material_ref) = world.get_material_ref(entity) {
let material_name = material_ref.name.clone();
if let Some(&index) = world
.resources
.material_registry
.registry
.name_to_index
.get(&material_name)
{
world
.resources
.material_registry
.registry
.remove_reference(index);
}
}
world
.resources
.mesh_render_state
.mark_entity_removed(entity);
}
}
world.despawn_entities(&descendants);
world.despawn_entities(&[gizmo.root]);
}
pub fn is_gizmo_entity(world: &World, gizmo: &GizmoState, entity: Entity) -> bool {
if entity == gizmo.root {
return true;
}
let descendants = crate::ecs::transform::queries::query_descendants(world, gizmo.root);
descendants.contains(&entity)
}
pub fn update_gizmo_transform(
world: &mut World,
gizmo: &GizmoState,
target_position: Vec3,
target_rotation: Quat,
camera_distance: f32,
) {
let config = GizmoConfig::default();
let scale = (camera_distance * config.scale_factor)
.max(config.min_scale)
.min(config.max_scale);
if let Some(transform) = world.get_local_transform(gizmo.root) {
let mut new_transform = *transform;
new_transform.translation = target_position;
new_transform.scale = nalgebra_glm::vec3(scale, scale, scale);
new_transform.rotation = target_rotation;
world.assign_local_transform(gizmo.root, new_transform);
}
}
fn set_entity_visible_recursive(world: &mut World, entity: Entity, visible: bool) {
if let Some(vis) = world.get_visibility_mut(entity) {
vis.visible = visible;
}
let descendants: Vec<Entity> = crate::ecs::transform::queries::query_descendants(world, entity)
.into_iter()
.collect();
for descendant in descendants {
if let Some(vis) = world.get_visibility_mut(descendant) {
vis.visible = visible;
}
}
}
pub fn show_entities(world: &mut World, entities: &[Entity]) {
for &entity in entities {
if let Some(visibility) = world.get_visibility_mut(entity) {
visibility.visible = true;
}
}
}
pub fn hide_entities(world: &mut World, entities: &[Entity]) {
for &entity in entities {
if let Some(visibility) = world.get_visibility_mut(entity) {
visibility.visible = false;
}
}
}
pub fn check_gizmo_axis_hit(
world: &World,
gizmo: &GizmoState,
picked_entity: Entity,
) -> Option<Vec3> {
let axes = [
(
gizmo.axis_entities.x_axis,
nalgebra_glm::vec3(1.0, 0.0, 0.0),
),
(
gizmo.axis_entities.y_axis,
nalgebra_glm::vec3(0.0, 1.0, 0.0),
),
(
gizmo.axis_entities.z_axis,
nalgebra_glm::vec3(0.0, 0.0, 1.0),
),
];
for (axis_entity, axis_vec) in axes.iter() {
if let Some(entity) = axis_entity
&& (picked_entity == *entity || is_child_of(world, picked_entity, *entity))
{
return Some(*axis_vec);
}
}
if let Some(center_entity) = gizmo.axis_entities.center_cube
&& (picked_entity == center_entity || is_child_of(world, picked_entity, center_entity))
{
return Some(nalgebra_glm::vec3(1.0, 1.0, 1.0));
}
let planes = [
(
gizmo.axis_entities.xy_plane,
nalgebra_glm::vec3(1.1, 1.1, 0.0),
),
(
gizmo.axis_entities.yz_plane,
nalgebra_glm::vec3(0.0, 1.1, 1.1),
),
(
gizmo.axis_entities.xz_plane,
nalgebra_glm::vec3(1.1, 0.0, 1.1),
),
];
for (plane_entity, plane_vec) in planes.iter() {
if let Some(entity) = plane_entity
&& (picked_entity == *entity || is_child_of(world, picked_entity, *entity))
{
return Some(*plane_vec);
}
}
None
}
fn is_child_of(world: &World, child: Entity, parent: Entity) -> bool {
let mut current = child;
while let Some(parent_comp) = world.get_parent(current) {
if let Some(parent_entity) = parent_comp.0 {
if parent_entity == parent {
return true;
}
current = parent_entity;
} else {
break;
}
}
false
}
fn set_entity_material_color(world: &mut World, entity: Entity, color: [f32; 4]) {
if let Some(material_ref) = world.get_material_ref(entity) {
let name = material_ref.name.clone();
if let Some(material) =
registry_entry_by_name_mut(&mut world.resources.material_registry.registry, &name)
{
material.base_color = color;
world
.resources
.mesh_render_state
.mark_material_dirty(entity);
}
}
}
pub fn highlight_gizmo_axis(world: &mut World, gizmo: &GizmoState, axis: Option<Vec3>) {
let axis_entities = &gizmo.axis_entities;
let axes = [
(axis_entities.x_axis, [0.7, 0.0, 0.0, 1.0]),
(axis_entities.y_axis, [0.0, 0.7, 0.0, 1.0]),
(axis_entities.z_axis, [0.0, 0.0, 0.7, 1.0]),
];
let highlighted_axis = axis.and_then(|a| {
if a.x > 0.5 && a.y < 0.1 && a.z < 0.1 {
Some(0)
} else if a.y > 0.5 && a.x < 0.1 && a.z < 0.1 {
Some(1)
} else if a.z > 0.5 && a.x < 0.1 && a.y < 0.1 {
Some(2)
} else {
None
}
});
let center_highlighted = axis.is_some_and(|a| a.x > 0.9 && a.y > 0.9 && a.z > 0.9);
let (xy_highlighted, yz_highlighted, xz_highlighted) =
axis.map_or((false, false, false), |a| {
if a.x > 1.05 && a.y > 1.05 {
(true, false, false)
} else if a.y > 1.05 && a.z > 1.05 {
(false, true, false)
} else if a.x > 1.05 && a.z > 1.05 {
(false, false, true)
} else {
(false, false, false)
}
});
for (index, (axis_entity, color)) in axes.iter().enumerate() {
if let Some(entity) = axis_entity {
let is_highlighted = Some(index) == highlighted_axis;
let base_color = if is_highlighted {
[1.0, 1.0, 0.0, 1.0]
} else {
*color
};
let children: Vec<Entity> =
crate::ecs::transform::queries::query_children(world, *entity);
for child in children {
set_entity_material_color(world, child, base_color);
}
}
}
if let Some(center_entity) = axis_entities.center_cube {
let color = if center_highlighted {
[1.0, 1.0, 0.0, 1.0]
} else {
[0.6, 0.6, 0.6, 1.0]
};
set_entity_material_color(world, center_entity, color);
}
if let Some(xy_plane) = axis_entities.xy_plane {
let color = if xy_highlighted {
[1.0, 1.0, 0.0, 0.7]
} else {
[0.4, 0.4, 0.0, 0.4]
};
set_entity_material_color(world, xy_plane, color);
}
if let Some(yz_plane) = axis_entities.yz_plane {
let color = if yz_highlighted {
[1.0, 1.0, 0.0, 0.7]
} else {
[0.0, 0.4, 0.4, 0.4]
};
set_entity_material_color(world, yz_plane, color);
}
if let Some(xz_plane) = axis_entities.xz_plane {
let color = if xz_highlighted {
[1.0, 1.0, 0.0, 0.7]
} else {
[0.4, 0.0, 0.4, 0.4]
};
set_entity_material_color(world, xz_plane, color);
}
}
#[derive(Clone, Copy)]
pub enum GizmoDragMode {
None,
Axis(Vec3),
Plane(Vec3),
Free,
}
pub fn set_gizmo_drag_visibility(world: &mut World, gizmo: &GizmoState, drag_mode: GizmoDragMode) {
let axis_entities = &gizmo.axis_entities;
match drag_mode {
GizmoDragMode::None => {
if let Some(x_axis) = axis_entities.x_axis {
set_entity_visible_recursive(world, x_axis, true);
}
if let Some(y_axis) = axis_entities.y_axis {
set_entity_visible_recursive(world, y_axis, true);
}
if let Some(z_axis) = axis_entities.z_axis {
set_entity_visible_recursive(world, z_axis, true);
}
if let Some(xy_plane) = axis_entities.xy_plane {
set_entity_visible_recursive(world, xy_plane, true);
}
if let Some(yz_plane) = axis_entities.yz_plane {
set_entity_visible_recursive(world, yz_plane, true);
}
if let Some(xz_plane) = axis_entities.xz_plane {
set_entity_visible_recursive(world, xz_plane, true);
}
if let Some(center_cube) = axis_entities.center_cube {
set_entity_visible_recursive(world, center_cube, true);
}
if let Some(x_line) = axis_entities.x_axis_line {
hide_entities(world, &[x_line]);
}
if let Some(y_line) = axis_entities.y_axis_line {
hide_entities(world, &[y_line]);
}
if let Some(z_line) = axis_entities.z_axis_line {
hide_entities(world, &[z_line]);
}
}
GizmoDragMode::Axis(axis) => {
let mut all_parts = Vec::new();
if let Some(x_axis) = axis_entities.x_axis {
all_parts.push(x_axis);
all_parts.extend(crate::ecs::transform::queries::query_descendants(
world, x_axis,
));
}
if let Some(y_axis) = axis_entities.y_axis {
all_parts.push(y_axis);
all_parts.extend(crate::ecs::transform::queries::query_descendants(
world, y_axis,
));
}
if let Some(z_axis) = axis_entities.z_axis {
all_parts.push(z_axis);
all_parts.extend(crate::ecs::transform::queries::query_descendants(
world, z_axis,
));
}
if let Some(xy_plane) = axis_entities.xy_plane {
all_parts.push(xy_plane);
all_parts.extend(crate::ecs::transform::queries::query_descendants(
world, xy_plane,
));
}
if let Some(yz_plane) = axis_entities.yz_plane {
all_parts.push(yz_plane);
all_parts.extend(crate::ecs::transform::queries::query_descendants(
world, yz_plane,
));
}
if let Some(xz_plane) = axis_entities.xz_plane {
all_parts.push(xz_plane);
all_parts.extend(crate::ecs::transform::queries::query_descendants(
world, xz_plane,
));
}
if let Some(center_cube) = axis_entities.center_cube {
all_parts.push(center_cube);
all_parts.extend(crate::ecs::transform::queries::query_descendants(
world,
center_cube,
));
}
hide_entities(world, &all_parts);
if let Some(x_line) = axis_entities.x_axis_line {
hide_entities(world, &[x_line]);
}
if let Some(y_line) = axis_entities.y_axis_line {
hide_entities(world, &[y_line]);
}
if let Some(z_line) = axis_entities.z_axis_line {
hide_entities(world, &[z_line]);
}
if axis.x > 0.5 {
if let Some(x_axis) = axis_entities.x_axis {
let mut to_show = vec![x_axis];
to_show.extend(crate::ecs::transform::queries::query_descendants(
world, x_axis,
));
show_entities(world, &to_show);
}
if let Some(x_line) = axis_entities.x_axis_line {
show_entities(world, &[x_line]);
}
} else if axis.y > 0.5 {
if let Some(y_axis) = axis_entities.y_axis {
let mut to_show = vec![y_axis];
to_show.extend(crate::ecs::transform::queries::query_descendants(
world, y_axis,
));
show_entities(world, &to_show);
}
if let Some(y_line) = axis_entities.y_axis_line {
show_entities(world, &[y_line]);
}
} else if axis.z > 0.5 {
if let Some(z_axis) = axis_entities.z_axis {
let mut to_show = vec![z_axis];
to_show.extend(crate::ecs::transform::queries::query_descendants(
world, z_axis,
));
show_entities(world, &to_show);
}
if let Some(z_line) = axis_entities.z_axis_line {
show_entities(world, &[z_line]);
}
}
}
GizmoDragMode::Plane(normal) => {
if let Some(center_cube) = axis_entities.center_cube {
set_entity_visible_recursive(world, center_cube, false);
}
if let Some(x_line) = axis_entities.x_axis_line {
hide_entities(world, &[x_line]);
}
if let Some(y_line) = axis_entities.y_axis_line {
hide_entities(world, &[y_line]);
}
if let Some(z_line) = axis_entities.z_axis_line {
hide_entities(world, &[z_line]);
}
if normal.z > 0.5 {
if let Some(xy_plane) = axis_entities.xy_plane {
set_entity_visible_recursive(world, xy_plane, true);
}
if let Some(yz_plane) = axis_entities.yz_plane {
set_entity_visible_recursive(world, yz_plane, false);
}
if let Some(xz_plane) = axis_entities.xz_plane {
set_entity_visible_recursive(world, xz_plane, false);
}
if let Some(x_axis) = axis_entities.x_axis {
set_entity_visible_recursive(world, x_axis, true);
}
if let Some(y_axis) = axis_entities.y_axis {
set_entity_visible_recursive(world, y_axis, true);
}
if let Some(z_axis) = axis_entities.z_axis {
set_entity_visible_recursive(world, z_axis, false);
}
if let Some(x_line) = axis_entities.x_axis_line {
show_entities(world, &[x_line]);
}
if let Some(y_line) = axis_entities.y_axis_line {
show_entities(world, &[y_line]);
}
} else if normal.x > 0.5 {
if let Some(yz_plane) = axis_entities.yz_plane {
set_entity_visible_recursive(world, yz_plane, true);
}
if let Some(xy_plane) = axis_entities.xy_plane {
set_entity_visible_recursive(world, xy_plane, false);
}
if let Some(xz_plane) = axis_entities.xz_plane {
set_entity_visible_recursive(world, xz_plane, false);
}
if let Some(y_axis) = axis_entities.y_axis {
set_entity_visible_recursive(world, y_axis, true);
}
if let Some(z_axis) = axis_entities.z_axis {
set_entity_visible_recursive(world, z_axis, true);
}
if let Some(x_axis) = axis_entities.x_axis {
set_entity_visible_recursive(world, x_axis, false);
}
if let Some(y_line) = axis_entities.y_axis_line {
show_entities(world, &[y_line]);
}
if let Some(z_line) = axis_entities.z_axis_line {
show_entities(world, &[z_line]);
}
} else {
if let Some(xz_plane) = axis_entities.xz_plane {
set_entity_visible_recursive(world, xz_plane, true);
}
if let Some(xy_plane) = axis_entities.xy_plane {
set_entity_visible_recursive(world, xy_plane, false);
}
if let Some(yz_plane) = axis_entities.yz_plane {
set_entity_visible_recursive(world, yz_plane, false);
}
if let Some(x_axis) = axis_entities.x_axis {
set_entity_visible_recursive(world, x_axis, true);
}
if let Some(z_axis) = axis_entities.z_axis {
set_entity_visible_recursive(world, z_axis, true);
}
if let Some(y_axis) = axis_entities.y_axis {
set_entity_visible_recursive(world, y_axis, false);
}
if let Some(x_line) = axis_entities.x_axis_line {
show_entities(world, &[x_line]);
}
if let Some(z_line) = axis_entities.z_axis_line {
show_entities(world, &[z_line]);
}
}
}
GizmoDragMode::Free => {
if let Some(x_line) = axis_entities.x_axis_line {
hide_entities(world, &[x_line]);
}
if let Some(y_line) = axis_entities.y_axis_line {
hide_entities(world, &[y_line]);
}
if let Some(z_line) = axis_entities.z_axis_line {
hide_entities(world, &[z_line]);
}
if let Some(x_axis) = axis_entities.x_axis {
set_entity_visible_recursive(world, x_axis, false);
}
if let Some(y_axis) = axis_entities.y_axis {
set_entity_visible_recursive(world, y_axis, false);
}
if let Some(z_axis) = axis_entities.z_axis {
set_entity_visible_recursive(world, z_axis, false);
}
if let Some(xy_plane) = axis_entities.xy_plane {
set_entity_visible_recursive(world, xy_plane, false);
}
if let Some(yz_plane) = axis_entities.yz_plane {
set_entity_visible_recursive(world, yz_plane, false);
}
if let Some(xz_plane) = axis_entities.xz_plane {
set_entity_visible_recursive(world, xz_plane, false);
}
if let Some(center_cube) = axis_entities.center_cube {
set_entity_visible_recursive(world, center_cube, true);
}
}
}
}