use rapier2d::prelude::*;
use rapier_testbed2d::Testbed;
use lyon::math::Point;
use lyon::path::PathEvent;
use lyon::tessellation::geometry_builder::*;
use lyon::tessellation::{self, FillOptions, FillTessellator};
use usvg::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Ground
*/
let ground_size = 25.0;
let rigid_body = RigidBodyBuilder::fixed();
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, 1.2);
colliders.insert_with_parent(collider, handle, &mut bodies);
let rigid_body = RigidBodyBuilder::fixed()
.rotation(std::f32::consts::FRAC_PI_2)
.translation(vector![ground_size, ground_size]);
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, 1.2);
colliders.insert_with_parent(collider, handle, &mut bodies);
let rigid_body = RigidBodyBuilder::fixed()
.rotation(std::f32::consts::FRAC_PI_2)
.translation(vector![-ground_size, ground_size]);
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, 1.2);
colliders.insert_with_parent(collider, handle, &mut bodies);
/*
* Create the trimeshes from a tessellated SVG.
*/
let mut fill_tess = FillTessellator::new();
let opt = usvg::Options::default();
let rtree = usvg::Tree::from_str(RAPIER_SVG_STR, &opt).unwrap();
let mut ith = 0;
for node in rtree.root().descendants() {
if let usvg::NodeKind::Path(ref p) = *node.borrow() {
let transform = node.transform();
if p.fill.is_some() {
let path = PathConvIter {
iter: p.data.iter(),
first: Point::new(0.0, 0.0),
prev: Point::new(0.0, 0.0),
deferred: None,
needs_end: false,
};
let mut mesh: VertexBuffers<_, u32> = VertexBuffers::new();
fill_tess
.tessellate(
path,
&FillOptions::tolerance(0.01),
&mut BuffersBuilder::new(&mut mesh, VertexCtor { prim_id: 0 }),
)
.expect("Tessellation failed.");
let angle = transform.get_rotate() as f32;
let (sx, sy) = (
transform.get_scale().0 as f32 * 0.2,
transform.get_scale().1 as f32 * 0.2,
);
let indices: Vec<_> = mesh.indices.chunks(3).map(|v| [v[0], v[1], v[2]]).collect();
let vertices: Vec<_> = mesh
.vertices
.iter()
.map(|v| point![v.position[0] * sx, v.position[1] * -sy])
.collect();
for k in 0..5 {
let collider = ColliderBuilder::trimesh(vertices.clone(), indices.clone())
.unwrap()
.contact_skin(0.2);
let rigid_body = RigidBodyBuilder::dynamic()
.translation(vector![ith as f32 * 8.0 - 20.0, 20.0 + k as f32 * 11.0])
.rotation(angle);
let handle = bodies.insert(rigid_body);
colliders.insert_with_parent(collider, handle, &mut bodies);
}
ith += 1;
}
}
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(point![0.0, 20.0], 17.0);
}
const RAPIER_SVG_STR: &str = r#"
"#;
pub struct PathConvIter<'a> {
iter: std::slice::Iter<'a, usvg::PathSegment>,
prev: Point,
first: Point,
needs_end: bool,
deferred: Option,
}
impl Iterator for PathConvIter<'_> {
type Item = PathEvent;
fn next(&mut self) -> Option {
if self.deferred.is_some() {
return self.deferred.take();
}
let next = self.iter.next();
match next {
Some(usvg::PathSegment::MoveTo { x, y }) => {
if self.needs_end {
let last = self.prev;
let first = self.first;
self.needs_end = false;
self.prev = Point::new(*x as f32, *y as f32);
self.deferred = Some(PathEvent::Begin { at: self.prev });
self.first = self.prev;
Some(PathEvent::End {
last,
first,
close: false,
})
} else {
self.first = Point::new(*x as f32, *y as f32);
Some(PathEvent::Begin { at: self.first })
}
}
Some(usvg::PathSegment::LineTo { x, y }) => {
self.needs_end = true;
let from = self.prev;
self.prev = Point::new(*x as f32, *y as f32);
Some(PathEvent::Line {
from,
to: self.prev,
})
}
Some(usvg::PathSegment::CurveTo {
x1,
y1,
x2,
y2,
x,
y,
}) => {
self.needs_end = true;
let from = self.prev;
self.prev = Point::new(*x as f32, *y as f32);
Some(PathEvent::Cubic {
from,
ctrl1: Point::new(*x1 as f32, *y1 as f32),
ctrl2: Point::new(*x2 as f32, *y2 as f32),
to: self.prev,
})
}
Some(usvg::PathSegment::ClosePath) => {
self.needs_end = false;
self.prev = self.first;
Some(PathEvent::End {
last: self.prev,
first: self.first,
close: true,
})
}
None => {
if self.needs_end {
self.needs_end = false;
let last = self.prev;
let first = self.first;
Some(PathEvent::End {
last,
first,
close: false,
})
} else {
None
}
}
}
}
}
pub struct VertexCtor {
pub prim_id: u32,
}
impl FillVertexConstructor for VertexCtor {
fn new_vertex(&mut self, vertex: tessellation::FillVertex) -> GpuVertex {
GpuVertex {
position: vertex.position().to_array(),
prim_id: self.prim_id,
}
}
}
impl StrokeVertexConstructor for VertexCtor {
fn new_vertex(&mut self, vertex: tessellation::StrokeVertex) -> GpuVertex {
GpuVertex {
position: vertex.position().to_array(),
prim_id: self.prim_id,
}
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct GpuVertex {
pub position: [f32; 2],
pub prim_id: u32,
}