Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 85b79a86ed | |||
| 78222ad55a | |||
| 6dc8e2a47f | |||
| a0007956f1 | |||
| cf44341c22 |
11
Cargo.toml
11
Cargo.toml
@@ -12,8 +12,11 @@ readme = "README.md"
|
||||
[dependencies]
|
||||
bevy = { version = "0.12.1", default-features = true}
|
||||
|
||||
fj-math = "0.47.0"
|
||||
fj-interop = "0.47.0"
|
||||
fj-core = "0.47.0"
|
||||
fj-export = "0.47.0"
|
||||
|
||||
rand = "0.8.5"
|
||||
|
||||
fj-math = "0.48.0"
|
||||
fj-interop = "0.48.0"
|
||||
fj-core = "0.48.0"
|
||||
fj-export = "0.48.0"
|
||||
|
||||
|
||||
BIN
fonts/FiraSans-Bold.ttf
Normal file
BIN
fonts/FiraSans-Bold.ttf
Normal file
Binary file not shown.
60
src/interop.rs
Normal file
60
src/interop.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
use bevy::prelude::{Component, Reflect, Resource};
|
||||
use fj_core::objects::{Sketch, Solid};
|
||||
use fj_math::{Point, Vector};
|
||||
use fj_interop::mesh::Mesh as FjMesh;
|
||||
use fj_core::storage::Handle as FjHandle;
|
||||
|
||||
#[derive(Component)]
|
||||
struct FjSolidWrapper {
|
||||
handle: fj_core::storage::Handle<Solid>,
|
||||
}
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
pub struct FjMeshWrapper {
|
||||
pub mesh: FjMesh<Point<3>>,
|
||||
pub handle: FjHandle<Solid>,
|
||||
pub sketch: Sketch,
|
||||
}
|
||||
|
||||
pub(crate) trait ToPoint3 {
|
||||
fn to_point3(&self) -> Point<3>;
|
||||
}
|
||||
|
||||
|
||||
impl ToPoint3 for bevy::prelude::Vec3 {
|
||||
fn to_point3(&self) -> fj_math::Point<3> {
|
||||
fj_math::Point { coords: Vector { components: [fj_math::Scalar::from_u64(0),fj_math::Scalar::from_u64(0),fj_math::Scalar::from_u64(0)] } }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait ToVec3 {
|
||||
fn to_vec3(&self) -> bevy::prelude::Vec3;
|
||||
}
|
||||
|
||||
impl ToVec3 for fj_math::Point<3> {
|
||||
fn to_vec3(&self) -> bevy::prelude::Vec3 {
|
||||
bevy::prelude::Vec3::new(self.x.into_f32(), self.y.into_f32(), self.z.into_f32())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToVec3 for fj_math::Vector<3> {
|
||||
fn to_vec3(&self) -> bevy::prelude::Vec3 {
|
||||
bevy::prelude::Vec3::new(self.x.into_f32(), self.y.into_f32(), self.z.into_f32())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait ToVec2 {
|
||||
fn to_vec2(&self) -> bevy::prelude::Vec2;
|
||||
}
|
||||
|
||||
impl crate::interop::ToVec2 for fj_math::Point<2> {
|
||||
fn to_vec2(&self) -> bevy::prelude::Vec2 {
|
||||
bevy::prelude::Vec2::new(self.u.into_f32(), self.v.into_f32())
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::interop::ToVec2 for fj_math::Vector<2> {
|
||||
fn to_vec2(&self) -> bevy::prelude::Vec2 {
|
||||
bevy::prelude::Vec2::new(self.u.into_f32(), self.v.into_f32())
|
||||
}
|
||||
}
|
||||
420
src/lib.rs
420
src/lib.rs
@@ -1,12 +1,17 @@
|
||||
pub mod mesh;
|
||||
pub mod interop;
|
||||
|
||||
// Importing Bevy ECS components and systems
|
||||
use crate::mesh::create_rectangle_mesh;
|
||||
use bevy::ecs::component::Component;
|
||||
use bevy::ecs::system::{Commands, Query};
|
||||
use bevy::ecs::entity::Entity;
|
||||
use bevy::ecs::query::Without;
|
||||
use bevy::ecs::system::ResMut;
|
||||
use crate::interop::{ToPoint3, ToVec3};
|
||||
|
||||
// Importing Bevy assets and rendering related components
|
||||
use bevy::prelude::{Mesh, shape};
|
||||
use bevy::prelude::*;
|
||||
use bevy::render::mesh::{Indices, PrimitiveTopology};
|
||||
use bevy::asset::Assets;
|
||||
use bevy::pbr::{PbrBundle, StandardMaterial};
|
||||
@@ -18,51 +23,29 @@ use bevy::utils::default;
|
||||
use bevy::app::{App, Plugin, Update};
|
||||
|
||||
// Importing Fj-core functionalities
|
||||
use fj_core::algorithms::approx::Tolerance;
|
||||
use fj_core::algorithms::bounding_volume::BoundingVolume;
|
||||
use fj_core::algorithms::sweep::Sweep;
|
||||
|
||||
use fj_core::algorithms::triangulate::Triangulate;
|
||||
use fj_core::objects::{Cycle, Region, Shell, Sketch, Solid};
|
||||
use fj_core::operations::{BuildCycle, BuildRegion, BuildSketch, Insert, Reverse, UpdateRegion, UpdateSketch};
|
||||
use fj_core::services::Services;
|
||||
use fj_core::objects::{Sketch, Solid};
|
||||
use fj_core::storage::Handle as FjHandle;
|
||||
|
||||
// Importing Fj-interop mesh
|
||||
use fj_interop::mesh::Mesh as FjMesh;
|
||||
|
||||
// Importing Fj-math and other standard functionalities
|
||||
use fj_math::{Aabb, Point, Scalar, Vector};
|
||||
|
||||
use fj_math::{Aabb, Line, Point, Scalar, Vector};
|
||||
use std::ops::Deref;
|
||||
use bevy::a11y::accesskit::Size;
|
||||
use bevy::math::Vec3;
|
||||
use fj_core::geometry::curve::GlobalPath;
|
||||
use bevy::ui::ZIndex::Global;
|
||||
use fj_core::geometry::{GlobalPath, SurfacePath};
|
||||
use fj_core::objects::Object::Surface;
|
||||
use fj_core::operations::holes::AddHole;
|
||||
use fj_core::operations::split::{SplitEdge, SplitFace, SplitHalfEdge};
|
||||
use rand::Rng;
|
||||
use crate::interop::FjMeshWrapper;
|
||||
use crate::mesh::{convert_mesh, LineList};
|
||||
|
||||
trait ToVec3 {
|
||||
fn to_vec3(&self) -> bevy::prelude::Vec3;
|
||||
}
|
||||
|
||||
impl ToVec3 for fj_math::Point<3> {
|
||||
fn to_vec3(&self) -> bevy::prelude::Vec3 {
|
||||
bevy::prelude::Vec3::new(self.x.into_f32(), self.y.into_f32(), self.z.into_f32())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToVec3 for fj_math::Vector<3> {
|
||||
fn to_vec3(&self) -> bevy::prelude::Vec3 {
|
||||
bevy::prelude::Vec3::new(self.x.into_f32(), self.y.into_f32(), self.z.into_f32())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct FjSolidWrapper{
|
||||
handle: fj_core::storage::Handle<Solid>,
|
||||
}
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
pub struct FjMeshWrapper {
|
||||
pub mesh: FjMesh<Point<3>>,
|
||||
pub handle: FjHandle<Solid>,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct FjConvertedFlag;
|
||||
@@ -75,196 +58,261 @@ impl Plugin for FjRenderPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn generate_uv_mapping(fj_mesh: &FjMesh<Point<3>>) -> Vec<[f32; 2]> {
|
||||
let mut uvs = Vec::new();
|
||||
|
||||
for vertex in fj_mesh.vertices() {
|
||||
let x = vertex.coords.x.into_f32();
|
||||
let y = vertex.coords.y.into_f32();
|
||||
// Here we're using x and y coordinates as u and v
|
||||
uvs.push([x, y]);
|
||||
uvs.push([x, y]);
|
||||
uvs.push([x, y]);
|
||||
uvs.push([x, y]);
|
||||
uvs.push([x, y]);
|
||||
uvs.push([x, y]);
|
||||
}
|
||||
uvs
|
||||
}
|
||||
|
||||
fn generate_normals(fj_mesh: &FjMesh<Point<3>>) -> Vec<[f32; 3]> {
|
||||
let mut normals = Vec::new();
|
||||
for triangle in fj_mesh.triangles() {
|
||||
let normal = triangle.inner.normal();
|
||||
normals.push([normal.x.into_f32(), normal.y.into_f32(), normal.z.into_f32()]);
|
||||
normals.push([normal.x.into_f32(), normal.y.into_f32(), normal.z.into_f32()]);
|
||||
normals.push([normal.x.into_f32(), normal.y.into_f32(), normal.z.into_f32()]);
|
||||
}
|
||||
normals
|
||||
}
|
||||
|
||||
fn generate_positions(fj_mesh: &FjMesh<Point<3>>) -> Vec<[f32; 3]> {
|
||||
let mut positions = Vec::new();
|
||||
|
||||
// Iterate through each triangle
|
||||
for triangle in fj_mesh.triangles() {
|
||||
// For each vertex index in the triangle
|
||||
for vertex_index in triangle.inner.points() {
|
||||
positions.push([vertex_index.x.into_f32(), vertex_index.y.into_f32(), vertex_index.z.into_f32()]);
|
||||
}
|
||||
}
|
||||
|
||||
positions
|
||||
}
|
||||
|
||||
fn generate_indices(fj_mesh: &FjMesh<Point<3>>) -> Vec<u32> {
|
||||
let mut num_positions = 0;
|
||||
|
||||
// Count the total number of positions (3 per triangle)
|
||||
for triangle in fj_mesh.triangles() {
|
||||
num_positions += 3;
|
||||
}
|
||||
|
||||
// Generate the indices [0, 1, 2, ..., num_positions-1]
|
||||
(0..num_positions as u32).collect()
|
||||
}
|
||||
|
||||
// Need to take a solid, and return all the data needed to create a Bevy Mesh from scratch
|
||||
pub fn convert_mesh(fj_mesh: &FjMesh<Point<3>>) -> Mesh {
|
||||
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
||||
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, generate_positions(&fj_mesh));
|
||||
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, generate_normals(&fj_mesh));
|
||||
// mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, generate_uv_mapping(&fj_mesh));
|
||||
mesh.set_indices(Some(Indices::U32(generate_indices(&fj_mesh))));
|
||||
mesh
|
||||
}
|
||||
|
||||
fn update_fj_model_system(
|
||||
mut commands: Commands,
|
||||
query: Query<(Entity, &FjMeshWrapper), Without<FjConvertedFlag>>,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
asset_server: Res<AssetServer>
|
||||
) {
|
||||
|
||||
for (entity, solid) in &query {
|
||||
|
||||
let bevy_mesh = convert_mesh(&solid.mesh);
|
||||
commands.entity(entity).insert(
|
||||
(
|
||||
PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(bevy_mesh.clone())),
|
||||
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
|
||||
transform: Transform::from_xyz(0.0, 0.0, 0.0),
|
||||
..default()
|
||||
},
|
||||
FjConvertedFlag
|
||||
|
||||
));
|
||||
(
|
||||
PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(bevy_mesh.clone())),
|
||||
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
|
||||
transform: Transform::from_xyz(0.0, 0.0, 0.0),
|
||||
..default()
|
||||
},
|
||||
FjConvertedFlag
|
||||
));
|
||||
add_debug_info_to_entity(&mut commands, solid, &mut meshes, &mut materials);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn add_debug_info_to_entity(mut commands: &mut Commands,
|
||||
fj_model: &FjMeshWrapper,
|
||||
mut meshes: &mut ResMut<Assets<Mesh>>,
|
||||
mut materials: &mut ResMut<Assets<StandardMaterial>>
|
||||
mut materials: &mut ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
// for region in fj_model.sketch.regions() {
|
||||
// for cycle in region.all_cycles() {
|
||||
// for half_edge in cycle.half_edges() {
|
||||
// match half_edge.path() {
|
||||
// SurfacePath::Circle(x) => {}
|
||||
// SurfacePath::Line(x) => {
|
||||
// render_line(commands, fj_model, meshes, materials, x)
|
||||
// }
|
||||
// }
|
||||
// // 1d point
|
||||
// half_edge.boundary().inner[0].coords;
|
||||
// half_edge.boundary().inner[1].coords;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
for shell in fj_model.handle.shells(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
for shell in fj_model.handle.shells() {
|
||||
println!("{:?}. shell", shell);
|
||||
for face in shell.faces() {
|
||||
|
||||
println!("{:?}. face", face);
|
||||
let surface = face.surface();
|
||||
let geom = surface.geometry();
|
||||
|
||||
let geom_sweep_vector = geom.v;
|
||||
|
||||
for edge in face.region().exterior().half_edges(){
|
||||
match edge.path() {
|
||||
SurfacePath::Circle(_) => {}
|
||||
SurfacePath::Line(x) => {
|
||||
let mut rng = rand::thread_rng();
|
||||
let color = Color::rgb(1.0, 0.,0.).into();
|
||||
|
||||
let mut origin = geom.point_from_surface_coords(x.origin()).to_xyz();
|
||||
let direction = geom.vector_from_surface_coords(x.direction()).to_xyz();
|
||||
let opposite_corner = Point{ coords: Vector{
|
||||
components: [
|
||||
Scalar::from(origin.x.into_f32()) + direction.x,
|
||||
Scalar::from(origin.y.into_f32()) + direction.y,
|
||||
Scalar::from(origin.z.into_f32()) + direction.z,
|
||||
]
|
||||
}};
|
||||
let line = GlobalPath::line_from_points([origin, opposite_corner]);
|
||||
match line.0 {
|
||||
GlobalPath::Circle(_) => {}
|
||||
GlobalPath::Line(x) => {
|
||||
render_line(commands, fj_model, meshes, materials, x, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match geom.u {
|
||||
GlobalPath::Circle(x) => {
|
||||
x.aabb();
|
||||
}
|
||||
GlobalPath::Line(x) => {
|
||||
let origin = x.origin();
|
||||
let direction = x.direction();
|
||||
let opposite_corner = Vec3::new(
|
||||
origin.x.into_f32() + direction.x.into_f32() + 0.01,
|
||||
origin.y.into_f32() + direction.y.into_f32() + 0.01,
|
||||
origin.z.into_f32() + direction.z.into_f32() + 0.01,
|
||||
);
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let red: f32 = rng.gen_range(0.0..1.0);
|
||||
let green: f32 = rng.gen_range(0.0..1.0);
|
||||
let blue: f32 = rng.gen_range(0.0..1.0);
|
||||
commands.spawn(( // line on base of sweep
|
||||
PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Box::from_corners(opposite_corner.into(), origin.to_vec3()))),
|
||||
material: materials.add(Color::rgb(red, green, blue).into()),
|
||||
transform: Transform::from_xyz(0.0, 0.0, 0.0),
|
||||
..default()
|
||||
},
|
||||
// RaycastPickTarget::default(), // <- Needed for the raycast backend.
|
||||
// PickableBundle::default() // <- This one too
|
||||
));
|
||||
commands.spawn(( // line on top of sweep, just offset by the sweep vector
|
||||
PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Box::from_corners(opposite_corner.into(), origin.to_vec3()))),
|
||||
material: materials.add(Color::rgb(red, green, blue).into()),
|
||||
transform: Transform::from_xyz(geom_sweep_vector.x.into_f32(), geom_sweep_vector.y.into_f32(), geom_sweep_vector.z.into_f32()),
|
||||
..default()
|
||||
},
|
||||
// RaycastPickTarget::default(), // <- Needed for the raycast backend.
|
||||
// PickableBundle::default() // <- This one too
|
||||
));
|
||||
commands.spawn(( // line following the sweep
|
||||
PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Box::from_corners(origin.to_vec3() + geom_sweep_vector.to_vec3(), origin.to_vec3() + 0.01))),
|
||||
material: materials.add(Color::rgb(red, green, blue).into()),
|
||||
transform: Transform::from_xyz(0.0, 0.0, 0.0),
|
||||
..default()
|
||||
},
|
||||
// RaycastPickTarget::default(), // <- Needed for the raycast backend.
|
||||
// PickableBundle::default() // <- This one too
|
||||
));
|
||||
commands.spawn(( // vertex
|
||||
PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.025 })),
|
||||
material: materials.add(Color::rgb(1.0, 1.0, 1.0).into()),
|
||||
transform: Transform::from_xyz(origin.to_xyz().x.into_f32(), origin.to_xyz().y.into_f32(), origin.to_xyz().z.into_f32()),
|
||||
..default()
|
||||
},
|
||||
// RaycastPickTarget::default(), // <- Needed for the raycast backend.
|
||||
// PickableBundle::default() // <- This one too
|
||||
));
|
||||
commands.spawn(( // swept vertex
|
||||
PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.025 })),
|
||||
material: materials.add(Color::rgb(1.0, 1.0, 1.0).into()),
|
||||
transform: Transform::from_xyz(
|
||||
origin.to_xyz().x.into_f32() + geom_sweep_vector.to_vec3().x,
|
||||
origin.to_xyz().y.into_f32() + geom_sweep_vector.to_vec3().y,
|
||||
origin.to_xyz().z.into_f32() + geom_sweep_vector.to_vec3().z,
|
||||
),
|
||||
// transform: Transform::from_scale(origin.to_vec3() + geom_sweep_vector.to_vec3()),
|
||||
..default()
|
||||
},
|
||||
// RaycastPickTarget::default(), // <- Needed for the raycast backend.
|
||||
// PickableBundle::default(), // <- This one too
|
||||
// let color = Color::rgb(red, green, blue).into();
|
||||
// render_line(commands, fj_model, meshes, materials, x, color);
|
||||
|
||||
// I want to insert a component when dragging starts, that contains
|
||||
// data about the exact ray hit location.
|
||||
// On::<Pointer<DragStart>>::run(run),
|
||||
// On::<Pointer<DragStart>>::target_insert(DragCaster::default()),
|
||||
// On::<Pointer<Drag>>::target_component_mut::<DragCaster>(|drag, mut caster| {
|
||||
// caster.hit_location = drag.hit.position.unwrap();
|
||||
//
|
||||
// // (*transform).translation = transform.translation + Vec3::new(-drag.delta.x / 100.0, 0.0, drag.delta.y / 100.0);
|
||||
// }),
|
||||
// On::<Pointer<Drag>>::target_component_mut::<DragCaster>(|drag, mut caster| {
|
||||
// drag.distance
|
||||
// // (*transform).translation = transform.translation + Vec3::new(-drag.delta.x / 100.0, 0.0, drag.delta.y / 100.0);
|
||||
// }),
|
||||
));
|
||||
// let origin = x.origin();
|
||||
// let direction = x.direction();
|
||||
// let opposite_corner = Vec3::new(
|
||||
// origin.x.into_f32() + direction.x.into_f32(),
|
||||
// origin.y.into_f32() + direction.y.into_f32(),
|
||||
// origin.z.into_f32() + direction.z.into_f32(),
|
||||
// );
|
||||
//
|
||||
// commands.spawn(( // line on top of sweep, just offset by the sweep vector
|
||||
// PbrBundle {
|
||||
// // mesh: meshes.add(Mesh::from(LineList {
|
||||
// // lines: vec![
|
||||
// // (opposite_corner.into(), origin.to_vec3()),
|
||||
// // ],
|
||||
// // })),
|
||||
// mesh: meshes.add(create_rectangle_mesh(opposite_corner, origin.to_vec3(), 0.01, 0.01)),
|
||||
// material: materials.add(Color::rgb(red, green, blue).into()),
|
||||
// transform: Transform::from_xyz(geom_sweep_vector.x.into_f32(), geom_sweep_vector.y.into_f32(), geom_sweep_vector.z.into_f32()),
|
||||
// ..default()
|
||||
// },
|
||||
// // RaycastPickTarget::default(), // <- Needed for the raycast backend.
|
||||
// // PickableBundle::default() // <- This one too
|
||||
// ));
|
||||
// commands.spawn(( // line following the sweep
|
||||
// PbrBundle {
|
||||
// mesh: meshes.add(create_rectangle_mesh(origin.to_vec3() + geom_sweep_vector.to_vec3(), origin.to_vec3(), 0.01, 0.01)),
|
||||
// material: materials.add(Color::rgb(red, green, blue).into()),
|
||||
// transform: Transform::from_xyz(0.0, 0.0, 0.0),
|
||||
// ..default()
|
||||
// },
|
||||
// // RaycastPickTarget::default(), // <- Needed for the raycast backend.
|
||||
// // PickableBundle::default() // <- This one too
|
||||
// ));
|
||||
// commands.spawn(( // swept vertex
|
||||
// PbrBundle {
|
||||
// mesh: meshes.add(Mesh::from(shape::Cube { size: 0.025 })),
|
||||
// material: materials.add(Color::rgb(1.0, 1.0, 1.0).into()),
|
||||
// transform: Transform::from_xyz(
|
||||
// origin.to_xyz().x.into_f32() + geom_sweep_vector.to_vec3().x,
|
||||
// origin.to_xyz().y.into_f32() + geom_sweep_vector.to_vec3().y,
|
||||
// origin.to_xyz().z.into_f32() + geom_sweep_vector.to_vec3().z,
|
||||
// ),
|
||||
// // transform: Transform::from_scale(origin.to_vec3() + geom_sweep_vector.to_vec3()),
|
||||
// ..default()
|
||||
// },
|
||||
// // RaycastPickTarget::default(), // <- Needed for the raycast backend.
|
||||
// // PickableBundle::default(), // <- This one too
|
||||
//
|
||||
// // I want to insert a component when dragging starts, that contains
|
||||
// // data about the exact ray hit location.
|
||||
// // On::<Pointer<DragStart>>::run(run),
|
||||
// // On::<Pointer<DragStart>>::target_insert(DragCaster::default()),
|
||||
// // On::<Pointer<Drag>>::target_component_mut::<DragCaster>(|drag, mut caster| {
|
||||
// // caster.hit_location = drag.hit.position.unwrap();
|
||||
// //
|
||||
// // // (*transform).translation = transform.translation + Vec3::new(-drag.delta.x / 100.0, 0.0, drag.delta.y / 100.0);
|
||||
// // }),
|
||||
// // On::<Pointer<Drag>>::target_component_mut::<DragCaster>(|drag, mut caster| {
|
||||
// // drag.distance
|
||||
// // // (*transform).translation = transform.translation + Vec3::new(-drag.delta.x / 100.0, 0.0, drag.delta.y / 100.0);
|
||||
// // }),
|
||||
// ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_line<const T: usize>(mut commands: &mut Commands,
|
||||
fj_model: &FjMeshWrapper,
|
||||
mut meshes: &mut ResMut<Assets<Mesh>>,
|
||||
mut materials: &mut ResMut<Assets<StandardMaterial>>,
|
||||
line: Line<T>,
|
||||
color: Color) {
|
||||
let origin = line.origin().to_xyz();
|
||||
let direction = line.direction().to_xyz();
|
||||
let opposite_corner = Vec3::new(
|
||||
origin.x.into_f32() + direction.x.into_f32(),
|
||||
origin.y.into_f32() + direction.y.into_f32(),
|
||||
origin.z.into_f32() + direction.z.into_f32(),
|
||||
);
|
||||
|
||||
commands.spawn(( // line on base of sweep
|
||||
PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(create_rectangle_mesh(opposite_corner, origin.to_vec3(), 0.01, 0.01))),
|
||||
// mesh: meshes.add(Mesh::from(shape::Box::from_corners(opposite_corner.into(), origin.to_vec3()))),
|
||||
material: materials.add(StandardMaterial::from(color)),
|
||||
transform: Transform::from_xyz(0.0, 0.0, 0.0),
|
||||
..default()
|
||||
},
|
||||
// RaycastPickTarget::default(), // <- Needed for the raycast backend.
|
||||
// PickableBundle::default() // <- This one too
|
||||
));
|
||||
commands.spawn(( // vertex
|
||||
PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.025 })),
|
||||
material: materials.add(Color::rgb(1.0, 1.0, 1.0).into()),
|
||||
transform: Transform::from_xyz(origin.to_xyz().x.into_f32(), origin.to_xyz().y.into_f32(), origin.to_xyz().z.into_f32()),
|
||||
..default()
|
||||
},
|
||||
// RaycastPickTarget::default(), // <- Needed for the raycast backend.
|
||||
// PickableBundle::default() // <- This one too
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
// Root node
|
||||
commands.spawn(NodeBundle {
|
||||
style: Style {
|
||||
flex_direction: FlexDirection::Column,
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}).with_children(|parent| {
|
||||
// Text node
|
||||
parent.spawn(TextBundle {
|
||||
text: Text::from_section(
|
||||
"This is some text",
|
||||
TextStyle {
|
||||
font: asset_server.load("fonts/FiraMono-Medium.ttf"),
|
||||
font_size: 40.0,
|
||||
color: Color::WHITE,
|
||||
},
|
||||
),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
// Checkbox (custom implementation)
|
||||
parent.spawn(NodeBundle {
|
||||
style: Style {
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}).with_children(|parent| {
|
||||
parent.spawn(TextBundle {
|
||||
text: Text::from_section(
|
||||
"X", // Simulating a checked state
|
||||
TextStyle {
|
||||
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
|
||||
font_size: 20.0,
|
||||
color: Color::BLACK,
|
||||
},
|
||||
),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
});
|
||||
*/
|
||||
162
src/mesh.rs
Normal file
162
src/mesh.rs
Normal file
@@ -0,0 +1,162 @@
|
||||
use bevy::math::Vec3;
|
||||
use bevy::prelude::Mesh;
|
||||
use bevy::render::mesh::{Indices, PrimitiveTopology};
|
||||
use fj_math::Point;
|
||||
use fj_interop::mesh::Mesh as FjMesh;
|
||||
use fj_core::storage::Handle as FjHandle;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LineList {
|
||||
pub lines: Vec<(Vec3, Vec3)>,
|
||||
}
|
||||
|
||||
impl From<LineList> for Mesh {
|
||||
fn from(line: LineList) -> Self {
|
||||
let vertices: Vec<_> = line.lines.into_iter().flat_map(|(a, b)| [a, b]).collect();
|
||||
|
||||
// This tells wgpu that the positions are list of lines
|
||||
// where every pair is a start and end point
|
||||
Mesh::new(PrimitiveTopology::LineList)
|
||||
// Add the vertices positions as an attribute
|
||||
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vertices)
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_uv_mapping(fj_mesh: &FjMesh<Point<3>>) -> Vec<[f32; 2]> {
|
||||
let mut uvs = Vec::new();
|
||||
|
||||
for vertex in fj_mesh.vertices() {
|
||||
let x = vertex.coords.x.into_f32();
|
||||
let y = vertex.coords.y.into_f32();
|
||||
// Here we're using x and y coordinates as u and v
|
||||
uvs.push([x, y]);
|
||||
uvs.push([x, y]);
|
||||
uvs.push([x, y]);
|
||||
uvs.push([x, y]);
|
||||
uvs.push([x, y]);
|
||||
uvs.push([x, y]);
|
||||
}
|
||||
uvs
|
||||
}
|
||||
|
||||
fn generate_normals(fj_mesh: &FjMesh<Point<3>>) -> Vec<[f32; 3]> {
|
||||
let mut normals = Vec::new();
|
||||
for triangle in fj_mesh.triangles() {
|
||||
let normal = triangle.inner.normal();
|
||||
normals.push([normal.x.into_f32(), normal.y.into_f32(), normal.z.into_f32()]);
|
||||
normals.push([normal.x.into_f32(), normal.y.into_f32(), normal.z.into_f32()]);
|
||||
normals.push([normal.x.into_f32(), normal.y.into_f32(), normal.z.into_f32()]);
|
||||
}
|
||||
normals
|
||||
}
|
||||
|
||||
fn generate_positions(fj_mesh: &FjMesh<Point<3>>) -> Vec<[f32; 3]> {
|
||||
let mut positions = Vec::new();
|
||||
|
||||
// Iterate through each triangle
|
||||
for triangle in fj_mesh.triangles() {
|
||||
// For each vertex index in the triangle
|
||||
for vertex_index in triangle.inner.points() {
|
||||
positions.push([vertex_index.x.into_f32(), vertex_index.y.into_f32(), vertex_index.z.into_f32()]);
|
||||
}
|
||||
}
|
||||
|
||||
positions
|
||||
}
|
||||
|
||||
fn generate_indices(fj_mesh: &FjMesh<Point<3>>) -> Vec<u32> {
|
||||
let mut num_positions = 0;
|
||||
|
||||
// Count the total number of positions (3 per triangle)
|
||||
for triangle in fj_mesh.triangles() {
|
||||
num_positions += 3;
|
||||
}
|
||||
|
||||
// Generate the indices [0, 1, 2, ..., num_positions-1]
|
||||
(0..num_positions as u32).collect()
|
||||
}
|
||||
|
||||
// Need to take a solid, and return all the data needed to create a Bevy Mesh from scratch
|
||||
pub fn convert_mesh(fj_mesh: &FjMesh<Point<3>>) -> Mesh {
|
||||
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
||||
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, generate_positions(&fj_mesh));
|
||||
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, generate_normals(&fj_mesh));
|
||||
// mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, generate_uv_mapping(&fj_mesh));
|
||||
mesh.set_indices(Some(Indices::U32(generate_indices(&fj_mesh))));
|
||||
mesh
|
||||
}
|
||||
|
||||
pub fn create_rectangle_mesh(p1: Vec3, p2: Vec3, width: f32, height: f32) -> Mesh {
|
||||
// Calculate direction vector from p1 to p2
|
||||
let direction = (p2 - p1).normalize();
|
||||
// Create arbitrary up vector
|
||||
let up = Vec3::Y;
|
||||
// Right vector for the rectangle width
|
||||
let right = direction.cross(up).normalize() * width * 0.5;
|
||||
// Up vector for rectangle height, ensuring it's perpendicular
|
||||
let up_perpendicular = direction.cross(right).normalize() * height * 0.5;
|
||||
|
||||
let vertices = [
|
||||
p1 - right - up_perpendicular, // Bottom-left of p1 face
|
||||
p1 + right - up_perpendicular, // Bottom-right of p1 face
|
||||
p1 + right + up_perpendicular, // Top-right of p1 face
|
||||
p1 - right + up_perpendicular, // Top-left of p1 face
|
||||
p2 - right - up_perpendicular, // Bottom-left of p2 face
|
||||
p2 + right - up_perpendicular, // Bottom-right of p2 face
|
||||
p2 + right + up_perpendicular, // Top-right of p2 face
|
||||
p2 - right + up_perpendicular, // Top-left of p2 face
|
||||
];
|
||||
|
||||
// Calculate face normals
|
||||
let front_normal = (vertices[1] - vertices[0]).cross(vertices[3] - vertices[0]).normalize();
|
||||
let back_normal = (vertices[5] - vertices[4]).cross(vertices[7] - vertices[4]).normalize();
|
||||
let right_normal = (vertices[5] - vertices[1]).cross(vertices[2] - vertices[1]).normalize();
|
||||
let left_normal = (vertices[0] - vertices[4]).cross(vertices[7] - vertices[4]).normalize();
|
||||
let top_normal = (vertices[2] - vertices[3]).cross(vertices[7] - vertices[3]).normalize();
|
||||
let bottom_normal = (vertices[1] - vertices[0]).cross(vertices[4] - vertices[0]).normalize();
|
||||
|
||||
let normals = vec![
|
||||
bottom_normal, bottom_normal, top_normal, top_normal, // Bottom and top for first quad
|
||||
bottom_normal, bottom_normal, top_normal, top_normal, // Bottom and top for second quad
|
||||
front_normal, front_normal, front_normal, front_normal, // Front face normals
|
||||
back_normal, back_normal, back_normal, back_normal, // Back face normals
|
||||
right_normal, right_normal, right_normal, right_normal, // Right face normals
|
||||
left_normal, left_normal, left_normal, left_normal, // Left face normals
|
||||
];
|
||||
|
||||
|
||||
// Convert positions and normals to the format expected by Bevy
|
||||
|
||||
// Creating a mesh
|
||||
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
||||
|
||||
// Insert positions
|
||||
let positions: Vec<[f32; 3]> = vertices.iter().map(|v| [v.x, v.y, v.z]).collect();
|
||||
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions);
|
||||
|
||||
// Insert normals (optional here, assuming all outwards for simplicity)
|
||||
let normals: Vec<[f32; 3]> = normals.iter().map(|n| [n.x, n.y, n.z]).collect();
|
||||
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
|
||||
|
||||
// Define two triangles for each face of the rectangle mesh
|
||||
|
||||
let indices = Indices::U32(vec![
|
||||
// Front face
|
||||
0, 2, 1, 0, 3, 2,
|
||||
// Back face
|
||||
4, 6, 5, 4, 7, 6,
|
||||
// Top face
|
||||
2, 3, 6, 6, 3, 7,
|
||||
// Bottom face
|
||||
0, 1, 5, 0, 5, 4,
|
||||
// Right face
|
||||
1, 2, 6, 1, 6, 5,
|
||||
// Left face
|
||||
0, 4, 7, 0, 7, 3,
|
||||
]);
|
||||
|
||||
|
||||
mesh.set_indices(Some(indices));
|
||||
|
||||
mesh
|
||||
}
|
||||
Reference in New Issue
Block a user