aboutsummaryrefslogtreecommitdiff
path: root/src_testbed/engine.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src_testbed/engine.rs')
-rw-r--r--src_testbed/engine.rs694
1 files changed, 694 insertions, 0 deletions
diff --git a/src_testbed/engine.rs b/src_testbed/engine.rs
new file mode 100644
index 0000000..62ab37e
--- /dev/null
+++ b/src_testbed/engine.rs
@@ -0,0 +1,694 @@
+#[cfg(feature = "dim3")]
+use kiss3d::camera::ArcBall as Camera;
+#[cfg(feature = "dim2")]
+use kiss3d::planar_camera::Sidescroll as Camera;
+use kiss3d::window::Window;
+
+use na::Point3;
+
+use crate::math::Point;
+use crate::objects::ball::Ball;
+use crate::objects::box_node::Box as BoxNode;
+use crate::objects::convex::Convex;
+use crate::objects::heightfield::HeightField;
+use crate::objects::node::{GraphicsNode, Node};
+use rapier::dynamics::{RigidBodyHandle, RigidBodySet};
+use rapier::geometry::{Collider, ColliderHandle, ColliderSet, Shape};
+//use crate::objects::capsule::Capsule;
+//use crate::objects::convex::Convex;
+//#[cfg(feature = "fluids")]
+//use crate::objects::fluid::Fluid as FluidNode;
+//#[cfg(feature = "dim3")]
+//use crate::objects::mesh::Mesh;
+//use crate::objects::plane::Plane;
+//#[cfg(feature = "dim2")]
+//use crate::objects::polyline::Polyline;
+//#[cfg(feature = "fluids")]
+//use crate::objects::FluidRenderingMode;
+use crate::objects::capsule::Capsule;
+use crate::objects::mesh::Mesh;
+use rand::{Rng, SeedableRng};
+use rand_pcg::Pcg32;
+use std::collections::HashMap;
+
+pub trait GraphicsWindow {
+ fn remove_graphics_node(&mut self, node: &mut GraphicsNode);
+ fn draw_graphics_line(&mut self, p1: &Point<f32>, p2: &Point<f32>, color: &Point3<f32>);
+}
+
+impl GraphicsWindow for Window {
+ fn remove_graphics_node(&mut self, node: &mut GraphicsNode) {
+ #[cfg(feature = "dim2")]
+ self.remove_planar_node(node);
+ #[cfg(feature = "dim3")]
+ self.remove_node(node);
+ }
+
+ fn draw_graphics_line(&mut self, p1: &Point<f32>, p2: &Point<f32>, color: &Point3<f32>) {
+ #[cfg(feature = "dim2")]
+ self.draw_planar_line(p1, p2, color);
+ #[cfg(feature = "dim3")]
+ self.draw_line(p1, p2, color);
+ }
+}
+
+pub struct GraphicsManager {
+ rand: Pcg32,
+ b2sn: HashMap<RigidBodyHandle, Vec<Node>>,
+ #[cfg(feature = "fluids")]
+ f2sn: HashMap<FluidHandle, FluidNode>,
+ #[cfg(feature = "fluids")]
+ boundary2sn: HashMap<BoundaryHandle, FluidNode>,
+ b2color: HashMap<RigidBodyHandle, Point3<f32>>,
+ b2wireframe: HashMap<RigidBodyHandle, bool>,
+ #[cfg(feature = "fluids")]
+ f2color: HashMap<FluidHandle, Point3<f32>>,
+ ground_color: Point3<f32>,
+ camera: Camera,
+ ground_handle: Option<RigidBodyHandle>,
+ #[cfg(feature = "fluids")]
+ fluid_rendering_mode: FluidRenderingMode,
+ #[cfg(feature = "fluids")]
+ render_boundary_particles: bool,
+}
+
+impl GraphicsManager {
+ pub fn new() -> GraphicsManager {
+ let mut camera;
+
+ #[cfg(feature = "dim3")]
+ {
+ camera = Camera::new(Point3::new(10.0, 10.0, 10.0), Point3::new(0.0, 0.0, 0.0));
+ camera.set_rotate_modifiers(Some(kiss3d::event::Modifiers::Control));
+ }
+
+ #[cfg(feature = "dim2")]
+ {
+ camera = Camera::new();
+ camera.set_zoom(50.0);
+ }
+
+ GraphicsManager {
+ camera,
+ rand: Pcg32::seed_from_u64(0),
+ b2sn: HashMap::new(),
+ #[cfg(feature = "fluids")]
+ f2sn: HashMap::new(),
+ #[cfg(feature = "fluids")]
+ boundary2sn: HashMap::new(),
+ b2color: HashMap::new(),
+ #[cfg(feature = "fluids")]
+ f2color: HashMap::new(),
+ ground_color: Point3::new(0.5, 0.5, 0.5),
+ b2wireframe: HashMap::new(),
+ ground_handle: None,
+ #[cfg(feature = "fluids")]
+ fluid_rendering_mode: FluidRenderingMode::StaticColor,
+ #[cfg(feature = "fluids")]
+ render_boundary_particles: false,
+ }
+ }
+
+ pub fn set_ground_handle(&mut self, handle: Option<RigidBodyHandle>) {
+ self.ground_handle = handle
+ }
+
+ #[cfg(feature = "fluids")]
+ pub fn set_fluid_rendering_mode(&mut self, mode: FluidRenderingMode) {
+ self.fluid_rendering_mode = mode;
+ }
+
+ #[cfg(feature = "fluids")]
+ pub fn enable_boundary_particles_rendering(&mut self, enabled: bool) {
+ self.render_boundary_particles = enabled;
+
+ for sn in self.boundary2sn.values_mut() {
+ sn.scene_node_mut().set_visible(enabled);
+ }
+ }
+
+ pub fn clear(&mut self, window: &mut Window) {
+ for sns in self.b2sn.values_mut() {
+ for sn in sns.iter_mut() {
+ if let Some(node) = sn.scene_node_mut() {
+ window.remove_graphics_node(node);
+ }
+ }
+ }
+
+ #[cfg(feature = "fluids")]
+ for sn in self.f2sn.values_mut().chain(self.boundary2sn.values_mut()) {
+ let node = sn.scene_node_mut();
+ window.remove_graphics_node(node);
+ }
+
+ self.b2sn.clear();
+ #[cfg(feature = "fluids")]
+ self.f2sn.clear();
+ #[cfg(feature = "fluids")]
+ self.boundary2sn.clear();
+ self.b2color.clear();
+ self.b2wireframe.clear();
+ self.rand = Pcg32::seed_from_u64(0);
+ }
+
+ pub fn remove_body_nodes(&mut self, window: &mut Window, body: RigidBodyHandle) {
+ if let Some(sns) = self.b2sn.get_mut(&body) {
+ for sn in sns.iter_mut() {
+ if let Some(node) = sn.scene_node_mut() {
+ window.remove_graphics_node(node);
+ }
+ }
+ }
+
+ self.b2sn.remove(&body);
+ }
+
+ #[cfg(feature = "fluids")]
+ pub fn set_fluid_color(&mut self, f: FluidHandle, color: Point3<f32>) {
+ self.f2color.insert(f, color);
+
+ if let Some(n) = self.f2sn.get_mut(&f) {
+ n.set_color(color)
+ }
+ }
+
+ pub fn set_body_color(&mut self, b: RigidBodyHandle, color: Point3<f32>) {
+ self.b2color.insert(b, color);
+
+ if let Some(ns) = self.b2sn.get_mut(&b) {
+ for n in ns.iter_mut() {
+ n.set_color(color)
+ }
+ }
+ }
+
+ pub fn set_body_wireframe(&mut self, b: RigidBodyHandle, enabled: bool) {
+ self.b2wireframe.insert(b, enabled);
+
+ if let Some(ns) = self.b2sn.get_mut(&b) {
+ for n in ns.iter_mut().filter_map(|n| n.scene_node_mut()) {
+ if enabled {
+ n.set_surface_rendering_activation(true);
+ n.set_lines_width(1.0);
+ } else {
+ n.set_surface_rendering_activation(false);
+ n.set_lines_width(1.0);
+ }
+ }
+ }
+ }
+
+ pub fn toggle_wireframe_mode(&mut self, colliders: &ColliderSet, enabled: bool) {
+ for n in self.b2sn.values_mut().flat_map(|val| val.iter_mut()) {
+ let force_wireframe = if let Some(collider) = colliders.get(n.collider()) {
+ collider.is_sensor()
+ || self
+ .b2wireframe
+ .get(&collider.parent())
+ .cloned()
+ .unwrap_or(false)
+ } else {
+ false
+ };
+
+ if let Some(node) = n.scene_node_mut() {
+ if force_wireframe || enabled {
+ node.set_lines_width(1.0);
+ node.set_surface_rendering_activation(false);
+ } else {
+ node.set_lines_width(0.0);
+ node.set_surface_rendering_activation(true);
+ }
+ }
+ }
+ }
+
+ fn gen_color(rng: &mut Pcg32) -> Point3<f32> {
+ let mut color: Point3<f32> = rng.gen();
+ color *= 1.5;
+ color.x = color.x.min(1.0);
+ color.y = color.y.min(1.0);
+ color.z = color.z.min(1.0);
+ color
+ }
+
+ fn alloc_color(&mut self, handle: RigidBodyHandle, is_static: bool) -> Point3<f32> {
+ let mut color = self.ground_color;
+
+ if !is_static {
+ match self.b2color.get(&handle).cloned() {
+ Some(c) => color = c,
+ None => color = Self::gen_color(&mut self.rand),
+ }
+ }
+
+ self.set_body_color(handle, color);
+
+ color
+ }
+
+ #[cfg(feature = "fluids")]
+ pub fn add_fluid(
+ &mut self,
+ window: &mut Window,
+ handle: FluidHandle,
+ fluid: &Fluid<f32>,
+ particle_radius: f32,
+ ) {
+ let rand = &mut self.rand;
+ let color = *self
+ .f2color
+ .entry(handle)
+ .or_insert_with(|| Self::gen_color(rand));
+
+ self.add_fluid_with_color(window, handle, fluid, particle_radius, color);
+ }
+
+ #[cfg(feature = "fluids")]
+ pub fn add_boundary(
+ &mut self,
+ window: &mut Window,
+ handle: BoundaryHandle,
+ boundary: &Boundary<f32>,
+ particle_radius: f32,
+ ) {
+ let color = self.ground_color;
+ let node = FluidNode::new(particle_radius, &boundary.positions, color, window);
+ self.boundary2sn.insert(handle, node);
+ }
+
+ #[cfg(feature = "fluids")]
+ pub fn add_fluid_with_color(
+ &mut self,
+ window: &mut Window,
+ handle: FluidHandle,
+ fluid: &Fluid<f32>,
+ particle_radius: f32,
+ color: Point3<f32>,
+ ) {
+ let node = FluidNode::new(particle_radius, &fluid.positions, color, window);
+ self.f2sn.insert(handle, node);
+ }
+
+ pub fn add(
+ &mut self,
+ window: &mut Window,
+ handle: RigidBodyHandle,
+ bodies: &RigidBodySet,
+ colliders: &ColliderSet,
+ ) {
+ let body = bodies.get(handle).unwrap();
+
+ let color = self
+ .b2color
+ .get(&handle)
+ .cloned()
+ .unwrap_or_else(|| self.alloc_color(handle, !body.is_dynamic()));
+
+ self.add_with_color(window, handle, bodies, colliders, color)
+ }
+
+ pub fn add_with_color(
+ &mut self,
+ window: &mut Window,
+ handle: RigidBodyHandle,
+ bodies: &RigidBodySet,
+ colliders: &ColliderSet,
+ color: Point3<f32>,
+ ) {
+ // let body = bodies.get(handle).unwrap();
+ let mut new_nodes = Vec::new();
+
+ for collider_handle in bodies[handle].colliders() {
+ let collider = &colliders[*collider_handle];
+ self.add_collider(window, *collider_handle, collider, color, &mut new_nodes);
+ }
+
+ new_nodes.iter_mut().for_each(|n| n.update(colliders));
+
+ for node in new_nodes.iter_mut().filter_map(|n| n.scene_node_mut()) {
+ if self.b2wireframe.get(&handle).cloned() == Some(true) {
+ node.set_lines_width(1.0);
+ node.set_surface_rendering_activation(false);
+ } else {
+ node.set_lines_width(0.0);
+ node.set_surface_rendering_activation(true);
+ }
+ }
+
+ let nodes = self.b2sn.entry(handle).or_insert_with(Vec::new);
+ nodes.append(&mut new_nodes);
+ }
+
+ fn add_collider(
+ &mut self,
+ window: &mut Window,
+ handle: ColliderHandle,
+ collider: &Collider,
+ color: Point3<f32>,
+ out: &mut Vec<Node>,
+ ) {
+ match collider.shape() {
+ Shape::Ball(ball) => {
+ out.push(Node::Ball(Ball::new(handle, ball.radius, color, window)))
+ }
+ Shape::Polygon(poly) => out.push(Node::Convex(Convex::new(
+ handle,
+ poly.vertices().to_vec(),
+ color,
+ window,
+ ))),
+ Shape::Cuboid(cuboid) => out.push(Node::Box(BoxNode::new(
+ handle,
+ cuboid.half_extents,
+ color,
+ window,
+ ))),
+ Shape::Capsule(capsule) => {
+ out.push(Node::Capsule(Capsule::new(handle, capsule, color, window)))
+ }
+ Shape::Triangle(triangle) => out.push(Node::Mesh(Mesh::new(
+ handle,
+ vec![triangle.a, triangle.b, triangle.c],
+ vec![Point3::new(0, 1, 2)],
+ color,
+ window,
+ ))),
+ Shape::Trimesh(trimesh) => out.push(Node::Mesh(Mesh::new(
+ handle,
+ trimesh.vertices().to_vec(),
+ trimesh
+ .indices()
+ .iter()
+ .map(|idx| na::convert(*idx))
+ .collect(),
+ color,
+ window,
+ ))),
+ Shape::HeightField(heightfield) => out.push(Node::HeightField(HeightField::new(
+ handle,
+ heightfield,
+ color,
+ window,
+ ))),
+ }
+ }
+
+ /*
+ fn add_plane(
+ &mut self,
+ window: &mut Window,
+ object: DefaultColliderHandle,
+ colliders: &DefaultColliderSet<f32>,
+ shape: &shape::Plane<f32>,
+ color: Point3<f32>,
+ out: &mut Vec<Node>,
+ ) {
+ let pos = colliders.get(object).unwrap().position();
+ let position = Point::from(pos.translation.vector);
+ let normal = pos * shape.normal();
+
+ out.push(Node::Plane(Plane::new(
+ object, colliders, &position, &normal, color, window,
+ )))
+ }
+
+ #[cfg(feature = "dim2")]
+ fn add_polyline(
+ &mut self,
+ window: &mut Window,
+ object: DefaultColliderHandle,
+ colliders: &DefaultColliderSet<f32>,
+ delta: Isometry<f32>,
+ shape: &shape::Polyline<f32>,
+ color: Point3<f32>,
+ out: &mut Vec<Node>,
+ ) {
+ let vertices = shape.points().to_vec();
+ let indices = shape.edges().iter().map(|e| e.indices).collect();
+
+ out.push(Node::Polyline(Polyline::new(
+ object, colliders, delta, vertices, indices, color, window,
+ )))
+ }
+
+ #[cfg(feature = "dim3")]
+ fn add_mesh(
+ &mut self,
+ window: &mut Window,
+ object: DefaultColliderHandle,
+ colliders: &DefaultColliderSet<f32>,
+ delta: Isometry<f32>,
+ shape: &TriMesh<f32>,
+ color: Point3<f32>,
+ out: &mut Vec<Node>,
+ ) {
+ let points = shape.points();
+ let faces = shape.faces();
+
+ let is = faces
+ .iter()
+ .map(|f| Point3::new(f.indices.x as u32, f.indices.y as u32, f.indices.z as u32))
+ .collect();
+
+ out.push(Node::Mesh(Mesh::new(
+ object,
+ colliders,
+ delta,
+ points.to_vec(),
+ is,
+ color,
+ window,
+ )))
+ }
+
+ fn add_heightfield(
+ &mut self,
+ window: &mut Window,
+ object: DefaultColliderHandle,
+ colliders: &DefaultColliderSet<f32>,
+ delta: Isometry<f32>,
+ heightfield: &shape::HeightField<f32>,
+ color: Point3<f32>,
+ out: &mut Vec<Node>,
+ ) {
+ out.push(Node::HeightField(HeightField::new(
+ object,
+ colliders,
+ delta,
+ heightfield,
+ color,
+ window,
+ )))
+ }
+
+ fn add_capsule(
+ &mut self,
+ window: &mut Window,
+ object: DefaultColliderHandle,
+ colliders: &DefaultColliderSet<f32>,
+ delta: Isometry<f32>,
+ shape: &shape::Capsule<f32>,
+ color: Point3<f32>,
+ out: &mut Vec<Node>,
+ ) {
+ let margin = colliders.get(object).unwrap().margin();
+ out.push(Node::Capsule(Capsule::new(
+ object,
+ colliders,
+ delta,
+ shape.radius() + margin,
+ shape.height(),
+ color,
+ window,
+ )))
+ }
+
+ fn add_ball(
+ &mut self,
+ window: &mut Window,
+ object: DefaultColliderHandle,
+ colliders: &DefaultColliderSet<f32>,
+ delta: Isometry<f32>,
+ shape: &shape::Ball<f32>,
+ color: Point3<f32>,
+ out: &mut Vec<Node>,
+ ) {
+ let margin = colliders.get(object).unwrap().margin();
+ out.push(Node::Ball(Ball::new(
+ object,
+ colliders,
+ delta,
+ shape.radius() + margin,
+ color,
+ window,
+ )))
+ }
+
+ fn add_box(
+ &mut self,
+ window: &mut Window,
+ object: DefaultColliderHandle,
+ colliders: &DefaultColliderSet<f32>,
+ delta: Isometry<f32>,
+ shape: &Cuboid<f32>,
+ color: Point3<f32>,
+ out: &mut Vec<Node>,
+ ) {
+ let margin = colliders.get(object).unwrap().margin();
+
+ out.push(Node::Box(Box::new(
+ object,
+ colliders,
+ delta,
+ shape.half_extents() + Vector::repeat(margin),
+ color,
+ window,
+ )))
+ }
+
+ #[cfg(feature = "dim2")]
+ fn add_convex(
+ &mut self,
+ window: &mut Window,
+ object: DefaultColliderHandle,
+ colliders: &DefaultColliderSet<f32>,
+ delta: Isometry<f32>,
+ shape: &ConvexPolygon<f32>,
+ color: Point3<f32>,
+ out: &mut Vec<Node>,
+ ) {
+ let points = shape.points();
+
+ out.push(Node::Convex(Convex::new(
+ object,
+ colliders,
+ delta,
+ points.to_vec(),
+ color,
+ window,
+ )))
+ }
+
+ #[cfg(feature = "dim3")]
+ fn add_convex(
+ &mut self,
+ window: &mut Window,
+ object: DefaultColliderHandle,
+ colliders: &DefaultColliderSet<f32>,
+ delta: Isometry<f32>,
+ shape: &ConvexHull<f32>,
+ color: Point3<f32>,
+ out: &mut Vec<Node>,
+ ) {
+ let mut chull = transformation::convex_hull(shape.points());
+ chull.replicate_vertices();
+ chull.recompute_normals();
+
+ out.push(Node::Convex(Convex::new(
+ object, colliders, delta, &chull, color, window,
+ )))
+ }
+ */
+
+ #[cfg(feature = "fluids")]
+ pub fn draw_fluids(&mut self, liquid_world: &LiquidWorld<f32>) {
+ for (i, fluid) in liquid_world.fluids().iter() {
+ if let Some(node) = self.f2sn.get_mut(&i) {
+ node.update_with_fluid(fluid, self.fluid_rendering_mode)
+ }
+ }
+
+ if self.render_boundary_particles {
+ for (i, boundary) in liquid_world.boundaries().iter() {
+ if let Some(node) = self.boundary2sn.get_mut(&i) {
+ node.update_with_boundary(boundary)
+ }
+ }
+ }
+ }
+
+ pub fn draw(&mut self, colliders: &ColliderSet, window: &mut Window) {
+ // use kiss3d::camera::Camera;
+ // println!(
+ // "camera eye {:?}, at: {:?}",
+ // self.camera.eye(),
+ // self.camera.at()
+ // );
+ for (_, ns) in self.b2sn.iter_mut() {
+ for n in ns.iter_mut() {
+ n.update(colliders);
+ n.draw(window);
+ }
+ }
+ }
+
+ // pub fn draw_positions(&mut self, window: &mut Window, rbs: &RigidBodies<f32>) {
+ // for (_, ns) in self.b2sn.iter_mut() {
+ // for n in ns.iter_mut() {
+ // let object = n.object();
+ // let rb = rbs.get(object).expect("Rigid body not found.");
+
+ // // if let WorldObjectBorrowed::RigidBody(rb) = object {
+ // let t = rb.position();
+ // let center = rb.center_of_mass();
+
+ // let rotmat = t.rotation.to_rotation_matrix().unwrap();
+ // let x = rotmat.column(0) * 0.25f32;
+ // let y = rotmat.column(1) * 0.25f32;
+ // let z = rotmat.column(2) * 0.25f32;
+
+ // window.draw_line(center, &(*center + x), &Point3::new(1.0, 0.0, 0.0));
+ // window.draw_line(center, &(*center + y), &Point3::new(0.0, 1.0, 0.0));
+ // window.draw_line(center, &(*center + z), &Point3::new(0.0, 0.0, 1.0));
+ // // }
+ // }
+ // }
+ // }
+
+ pub fn camera(&self) -> &Camera {
+ &self.camera
+ }
+
+ pub fn camera_mut(&mut self) -> &mut Camera {
+ &mut self.camera
+ }
+
+ #[cfg(feature = "dim3")]
+ pub fn look_at(&mut self, eye: Point<f32>, at: Point<f32>) {
+ self.camera.look_at(eye, at);
+ }
+
+ #[cfg(feature = "dim2")]
+ pub fn look_at(&mut self, at: Point<f32>, zoom: f32) {
+ self.camera.look_at(at, zoom);
+ }
+
+ pub fn body_nodes(&self, handle: RigidBodyHandle) -> Option<&Vec<Node>> {
+ self.b2sn.get(&handle)
+ }
+
+ pub fn body_nodes_mut(&mut self, handle: RigidBodyHandle) -> Option<&mut Vec<Node>> {
+ self.b2sn.get_mut(&handle)
+ }
+
+ pub fn nodes(&self) -> impl Iterator<Item = &Node> {
+ self.b2sn.values().flat_map(|val| val.iter())
+ }
+
+ pub fn nodes_mut(&mut self) -> impl Iterator<Item = &mut Node> {
+ self.b2sn.values_mut().flat_map(|val| val.iter_mut())
+ }
+
+ #[cfg(feature = "dim3")]
+ pub fn set_up_axis(&mut self, up_axis: na::Vector3<f32>) {
+ self.camera.set_up_axis(up_axis);
+ }
+}
+
+impl Default for GraphicsManager {
+ fn default() -> Self {
+ Self::new()
+ }
+}