use crate::ecs::material::resources::material_registry_insert;
use crate::prelude::*;
use super::{
AxisArrowParams, AxisWithCubeParams, GizmoAxisEntities, GizmoConfig, GizmoMode, GizmoState,
RotationRingParams, set_gizmo_layer,
};
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.core.get_name_mut(gizmo_root) {
name.0 = name_str.to_string();
}
if let Some(transform) = world.core.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.core.get_name_mut(gizmo_root) {
name.0 = "Scale Gizmo".to_string();
}
if let Some(transform) = world.core.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.core.get_name_mut(gizmo_root) {
name.0 = "Rotation Gizmo".to_string();
}
set_gizmo_layer(world, gizmo_root);
if let Some(transform) = world.core.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.core.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.core.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.core.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.core.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.core.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.core.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.core.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
.core
.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.core.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.core.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.core.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
.core
.set_material_ref(cone_entity, MaterialRef::new(cone_material_name));
if let Some(bounding) = world.core.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.core.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.core.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.core.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
.core
.set_material_ref(center_cube, MaterialRef::new(material_name));
if let Some(visibility) = world.core.get_visibility_mut(center_cube) {
visibility.visible = true;
}
if let Some(bounding) = world.core.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.core.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.core.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.core.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.core.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.core.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.core.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
.core
.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.core.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.core.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.core.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
.core
.set_material_ref(cube_entity, MaterialRef::new(cube_material_name));
if let Some(bounding) = world.core.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.core.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.core.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.core.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.core.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.core.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.core.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.core.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.core.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
.core
.set_material_ref(plane_entity, MaterialRef::new(material_name));
if let Some(visibility) = world.core.get_visibility_mut(plane_entity) {
visibility.visible = true;
}
if let Some(bounding) = world.core.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.core.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.core.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.core.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
.core
.set_material_ref(line_entity, MaterialRef::new(material_name));
if let Some(visibility) = world.core.get_visibility_mut(line_entity) {
visibility.visible = false;
}
line_entity
}