nphysics_testbed3d 0.10.0

Testbed for the 3-dimensional physics engine in Rust.
use crate::objects::node::GraphicsNode;
use kiss3d::window::Window;
use na::{Point3, RealField, Vector3};
use nphysics::math::{Point, Vector};
use salva::object::{Boundary, Fluid as SalvaFluid};
use simba::scalar::SubsetOf;

#[derive(Copy, Clone, Debug)]
pub enum FluidRenderingMode {
    VelocityColor { min: f32, max: f32 },
    StaticColor,
}

pub struct Fluid {
    radius: f32,
    color: Point3<f32>,
    base_color: Point3<f32>,
    gfx: GraphicsNode,
    balls_gfx: Vec<GraphicsNode>,
}

impl Fluid {
    pub fn new<N: RealField>(
        radius: f32,
        centers: &[Point<N>],
        color: Point3<f32>,
        window: &mut Window,
    ) -> Fluid {
        #[cfg(feature = "dim2")]
        let mut gfx = window.add_planar_group();
        #[cfg(feature = "dim3")]
        let mut gfx = window.add_group();

        let mut balls_gfx = Vec::new();

        for c in centers {
            #[cfg(feature = "dim2")]
            let mut ball_gfx = gfx.add_circle(radius);
            #[cfg(feature = "dim3")]
            let mut ball_gfx = gfx.add_sphere(radius);
            let c: Vector<f64> = na::convert_unchecked(c.coords);
            let c: Vector<f32> = na::convert(c);
            ball_gfx.set_local_translation(c.into());
            balls_gfx.push(ball_gfx);
        }

        let mut res = Fluid {
            radius,
            color,
            base_color: color,
            gfx,
            balls_gfx,
        };

        res.gfx.set_color(color.x, color.y, color.z);
        res
    }

    pub fn select(&mut self) {
        self.color = Point3::new(1.0, 0.0, 0.0);
    }

    pub fn unselect(&mut self) {
        self.color = self.base_color;
    }

    pub fn set_color(&mut self, color: Point3<f32>) {
        self.gfx.set_color(color.x, color.y, color.z);
        self.color = color;
        self.base_color = color;
    }

    fn update<N: RealField>(
        &mut self,
        centers: &[Point<N>],
        velocities: &[Vector<N>],
        mode: FluidRenderingMode,
    ) {
        if centers.len() > self.balls_gfx.len() {
            for _ in 0..centers.len() - self.balls_gfx.len() {
                #[cfg(feature = "dim2")]
                let ball_gfx = self.gfx.add_circle(self.radius);
                #[cfg(feature = "dim3")]
                let ball_gfx = self.gfx.add_sphere(self.radius);
                self.balls_gfx.push(ball_gfx);
            }
        }

        for ball_gfx in &mut self.balls_gfx[centers.len()..] {
            ball_gfx.set_visible(false);
        }

        for (i, (pt, ball)) in centers.iter().zip(self.balls_gfx.iter_mut()).enumerate() {
            ball.set_visible(true);
            let c: Vector<f64> = na::convert_unchecked(pt.coords);
            let c: Vector<f32> = na::convert(c);
            ball.set_local_translation(c.into());

            let color = match mode {
                FluidRenderingMode::StaticColor => self.base_color,
                FluidRenderingMode::VelocityColor { min, max } => {
                    let start = self.base_color.coords;
                    let end = Vector3::new(1.0, 0.0, 0.0);
                    let vel: Vector<f64> = na::convert_unchecked(velocities[i]);
                    let vel: Vector<f32> = na::convert(vel);
                    let t = (vel.norm() - min) / (max - min);
                    start.lerp(&end, na::clamp(t, 0.0, 1.0)).into()
                }
            };

            ball.set_color(color.x, color.y, color.z);
        }
    }

    pub fn update_with_boundary<N: RealField>(&mut self, boundary: &Boundary<N>) {
        self.update(&boundary.positions, &[], FluidRenderingMode::StaticColor)
    }

    pub fn update_with_fluid<N: RealField>(
        &mut self,
        fluid: &SalvaFluid<N>,
        rendering_mode: FluidRenderingMode,
    ) {
        self.update(&fluid.positions, &fluid.velocities, rendering_mode)
    }

    pub fn scene_node(&self) -> &GraphicsNode {
        &self.gfx
    }

    pub fn scene_node_mut(&mut self) -> &mut GraphicsNode {
        &mut self.gfx
    }
}