diff --git a/Cargo.toml b/Cargo.toml index ce715d3..5fad036 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT" description = "Generalized hypercube visualizer" readme = ".github/README.md" repository = "https://github.com/ndavd/ncube" -exclude = [".github/demo.gif"] +exclude = [".github/demo.gif", ".github/workflows"] keywords = ["simulation", "hypercube", "bevy", "mathematics", "tesseract"] categories = ["simulation", "mathematics", "visualization", "graphics"] diff --git a/src/main.rs b/src/main.rs index dd2c86b..09e4ee6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ fn main() { .init_resource::() .init_resource::() .init_resource::() + .init_resource::() .add_plugins(( DefaultPlugins, camera::CameraPlugin, @@ -135,6 +136,14 @@ impl std::default::Default for NCubeEdgeThickness { } } +#[derive(Resource, Deref, DerefMut)] +pub struct NCubeUnlit(bool); +impl std::default::Default for NCubeUnlit { + fn default() -> Self { + Self(false) + } +} + fn spawn_hypercube( mut commands: Commands, mut meshes: ResMut>, @@ -144,6 +153,7 @@ fn spawn_hypercube( mut ncube_rotations: ResMut, mut ncube_planes_of_rotation: ResMut, mut ncube_vertices_3d: ResMut, + ncube_unlit: Res, ncube_edge_color: Res, ncube_face_color: Res, q_ncube_entities: Query>, @@ -186,6 +196,7 @@ fn spawn_hypercube( base_color: **ncube_edge_color, double_sided: true, cull_mode: None, + unlit: **ncube_unlit, ..default() }), transform: edge::Edge::transform( @@ -209,8 +220,11 @@ fn spawn_hypercube( ncube_vertices_3d[*k], ], ); - let normal = ncube_vertices_3d[*i].normal(&ncube_vertices_3d[*j], &ncube_vertices_3d[*k]); - mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, vec![normal; 3]); + if !**ncube_unlit { + let normal = + ncube_vertices_3d[*i].normal(&ncube_vertices_3d[*j], &ncube_vertices_3d[*k]); + mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, vec![normal; 3]); + } commands.spawn(( MaterialMeshBundle { mesh: meshes.add(mesh.into()).into(), @@ -219,6 +233,7 @@ fn spawn_hypercube( alpha_mode: AlphaMode::Add, double_sided: true, cull_mode: None, + unlit: **ncube_unlit, ..default() }), ..default() @@ -235,6 +250,7 @@ fn update_ncube_meshes( ncube_face_color: Res, ncube_edge_thickness: Res, ncube_vertices_3d: Res, + ncube_unlit: Res, mut q_edges: Query<(&mut Transform, &Handle), With>, q_face_handles: Query<(&Handle, &Handle), With>, mut meshes: ResMut>, @@ -250,6 +266,14 @@ fn update_ncube_meshes( materials.get_mut(material_handle).unwrap().base_color = **ncube_face_color; }); } + if ncube_unlit.is_changed() { + q_edges.iter().for_each(|(_, material_handle)| { + materials.get_mut(material_handle).unwrap().unlit = **ncube_unlit; + }); + q_face_handles.iter().for_each(|(_, material_handle)| { + materials.get_mut(material_handle).unwrap().unlit = **ncube_unlit; + }); + } if !ncube.is_changed() { return; @@ -273,14 +297,16 @@ fn update_ncube_meshes( .for_each(|(i, (mesh_handle, _))| { if let Some(face) = ncube.faces.0.get(i) { let mesh = meshes.get_mut(mesh_handle).unwrap(); - mesh.insert_attribute( - Mesh::ATTRIBUTE_NORMAL, - vec![ - ncube_vertices_3d[face.0] - .normal(&ncube_vertices_3d[face.1], &ncube_vertices_3d[face.2]); - 3 - ], - ); + if !**ncube_unlit { + mesh.insert_attribute( + Mesh::ATTRIBUTE_NORMAL, + vec![ + ncube_vertices_3d[face.0] + .normal(&ncube_vertices_3d[face.1], &ncube_vertices_3d[face.2]); + 3 + ], + ); + } mesh.insert_attribute( Mesh::ATTRIBUTE_POSITION, vec![ diff --git a/src/settings.rs b/src/settings.rs index ca2a6ba..e27c653 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,3 +1,4 @@ +use crate::camera::get_default_camera_transform; use crate::ncube::NCube as InnerNCube; use crate::NCube; use crate::NCubeDimension; @@ -7,6 +8,7 @@ use crate::NCubeFaceColor; use crate::NCubeIsPaused; use crate::NCubePlanesOfRotation; use crate::NCubeRotations; +use crate::NCubeUnlit; use crate::NCubeVertices3D; use crate::S; use bevy::prelude::*; @@ -27,15 +29,31 @@ struct CameraTransform { rotation: Quat, scale: Vec3, } +impl std::default::Default for CameraTransform { + fn default() -> Self { + let transform = get_default_camera_transform(); + Self { + translation: transform.translation, + rotation: transform.rotation, + scale: transform.scale, + } + } +} #[derive(Debug, serde::Serialize, serde::Deserialize)] struct NCubeData { dimension: usize, rotations: Vec<(usize, usize, f32, f32)>, + #[serde(default)] + camera_transform: CameraTransform, + #[serde(default)] edge_thickness: f32, + #[serde(default)] edge_color: Color, + #[serde(default)] face_color: Color, - camera_transform: CameraTransform, + #[serde(default)] + unlit: bool, } #[derive(Resource, Deref, DerefMut, Default)] @@ -50,6 +68,7 @@ fn info_panel( mut ncube_face_color: ResMut, mut ncube_edge_thickness: ResMut, mut ncube_vertices_3d: ResMut, + mut ncube_unlit: ResMut, mut ncube_is_paused: ResMut, mut contexts: EguiContexts, mut q_camera_transform: Query<&mut Transform, With>, @@ -85,6 +104,12 @@ fn info_panel( ui.label(format!("{}", ncube.faces.0.len() / 2)); ui.end_row(); + ui.label("realistic lighting:"); + let mut lit = !**ncube_unlit; + ui.add(egui::Checkbox::new(&mut lit, "")); + **ncube_unlit = !lit; + ui.end_row(); + ui.label("edge thickness:"); ui.add(egui::Slider::new(&mut **ncube_edge_thickness, 0.0..=0.025)); ui.end_row(); @@ -165,6 +190,7 @@ fn info_panel( rotation: camera_transform.rotation, scale: camera_transform.scale, }, + unlit: **ncube_unlit, }; serde_json::to_writer_pretty(&mut file, &ncube_data) .unwrap_or_else(|_| {}); @@ -188,31 +214,34 @@ fn info_panel( FileDragAndDrop::DroppedFile { path_buf, .. } => { let file = std::fs::File::open(&path_buf).unwrap(); let reader = std::io::BufReader::new(file); - if let Ok(data) = - serde_json::from_reader::<_, NCubeData>(reader) - { - *q_camera_transform.get_single_mut().unwrap() = Transform { - translation: data.camera_transform.translation, - scale: data.camera_transform.scale, - rotation: data.camera_transform.rotation, - }; - **ncube_is_paused = true; - **ncube_edge_thickness = data.edge_thickness; - **ncube_edge_color = data.edge_color; - **ncube_face_color = data.face_color; - **ncube_dimension = data.dimension; - **ncube = InnerNCube::new(**ncube_dimension, S); - **ncube_rotations = std::collections::HashMap::new(); - **ncube_planes_of_rotation = Vec::new(); - let mut angles = Vec::new(); - for (d1, d2, angle, vel) in data.rotations { - ncube_rotations.insert((d1, d2), (angle, vel)); - ncube_planes_of_rotation.push((d1, d2)); - angles.push(angle); + match serde_json::from_reader::<_, NCubeData>(reader) { + Ok(data) => { + *q_camera_transform.get_single_mut().unwrap() = + Transform { + translation: data.camera_transform.translation, + scale: data.camera_transform.scale, + rotation: data.camera_transform.rotation, + }; + **ncube_is_paused = true; + **ncube_edge_thickness = data.edge_thickness; + **ncube_edge_color = data.edge_color; + **ncube_face_color = data.face_color; + **ncube_unlit = data.unlit; + **ncube_dimension = data.dimension; + **ncube = InnerNCube::new(**ncube_dimension, S); + **ncube_rotations = std::collections::HashMap::new(); + **ncube_planes_of_rotation = Vec::new(); + let mut angles = Vec::new(); + for (d1, d2, angle, vel) in data.rotations { + ncube_rotations.insert((d1, d2), (angle, vel)); + ncube_planes_of_rotation.push((d1, d2)); + angles.push(angle); + } + **ncube_vertices_3d = ncube + .rotate(&ncube_planes_of_rotation, &angles) + .perspective_project_vertices(); } - **ncube_vertices_3d = ncube - .rotate(&ncube_planes_of_rotation, &angles) - .perspective_project_vertices(); + Err(e) => println!("ERR {e}"), } **is_hovering_file = false; }