pack.rs

4.7 kB · rust · 155 lines

1use super::vec::Vec3;2use mrlycore::colors::{BLUE, GREEN, RED};34/// The WGSL shader that consumes the packed wire format.5pub const MESH_WGSL: &str = include_str!("mesh.wgsl");67/// A colored line segment.8pub struct Edge {9    /// The two endpoints.10    pub ends: [Vec3; 2],11    /// The RGBA color.12    pub color: [u8; 4],13}1415/// A builder packing triangles and lines into one flat float buffer.16#[derive(Default)]17pub struct Pack {18    tris: Vec<f32>,19    lines: Vec<f32>,20}2122impl Pack {23    /// Builds an empty pack.24    pub fn new() -> Pack {25        Pack::default()26    }27    /// Packs one triangle, writing position and normal per vertex.28    pub fn face(&mut self, verts: [Vec3; 3], normal: Vec3) {29        for v in verts {30            self.tris31                .extend([v.x, v.y, v.z, normal.x, normal.y, normal.z]);32        }33    }34    /// Packs a quad as two triangles sharing the normal.35    pub fn quad(&mut self, verts: [Vec3; 4], normal: Vec3) {36        self.face([verts[0], verts[1], verts[2]], normal);37        self.face([verts[0], verts[2], verts[3]], normal);38    }39    /// Packs one line, writing position, spin flag and color per endpoint.40    pub fn line(&mut self, a: Vec3, b: Vec3, spins: bool, color: [u8; 4]) {41        for v in [a, b] {42            self.lines43                .extend([v.x, v.y, v.z, if spins { 1.0 } else { 0.0 }]);44            self.lines.extend(color.map(|c| c as f32 / 255.0));45        }46    }47    /// Closes the pack into one buffer, the two section lengths first.48    pub fn buffer(self) -> Vec<f32> {49        let mut out = vec![self.tris.len() as f32, self.lines.len() as f32];50        out.extend(self.tris);51        out.extend(self.lines);52        out53    }54}5556/// Builds the three colored axes and a faint floor grid in the given ink.57pub fn axis_edges(ink: [u8; 4]) -> Vec<Edge> {58    let o = Vec3::new(0.0, -1.0, 0.0);59    let mut out = vec![60        Edge {61            ends: [o, Vec3::new(1.4, -1.0, 0.0)],62            color: [RED.r, RED.g, RED.b, 255],63        },64        Edge {65            ends: [o, Vec3::new(0.0, 0.4, 0.0)],66            color: [GREEN.r, GREEN.g, GREEN.b, 255],67        },68        Edge {69            ends: [o, Vec3::new(0.0, -1.0, 1.4)],70            color: [BLUE.r, BLUE.g, BLUE.b, 255],71        },72    ];73    let faint = [ink[0], ink[1], ink[2], 64];74    for k in 0..=6 {75        let c = -1.2 + 0.4 * k as f32;76        out.push(Edge {77            ends: [Vec3::new(c, -1.0, -1.2), Vec3::new(c, -1.0, 1.2)],78            color: faint,79        });80        out.push(Edge {81            ends: [Vec3::new(-1.2, -1.0, c), Vec3::new(1.2, -1.0, c)],82            color: faint,83        });84    }85    out86}8788#[cfg(test)]89mod tests {90    use super::*;9192    #[test]93    fn the_pack_lays_out_the_wire_format() {94        let mut pack = Pack::new();95        pack.face(96            [97                Vec3::new(0.0, 0.0, 0.0),98                Vec3::new(1.0, 0.0, 0.0),99                Vec3::new(0.0, 1.0, 0.0),100            ],101            Vec3::new(0.0, 0.0, 1.0),102        );103        pack.line(104            Vec3::new(0.0, 0.0, 0.0),105            Vec3::new(0.0, 0.0, 1.0),106            true,107            [255, 0, 0, 128],108        );109        let buf = pack.buffer();110        assert_eq!(buf[0], 18.0);111        assert_eq!(buf[1], 16.0);112        assert_eq!(&buf[2..8], &[0.0, 0.0, 0.0, 0.0, 0.0, 1.0]);113        assert_eq!(&buf[8..14], &[1.0, 0.0, 0.0, 0.0, 0.0, 1.0]);114        assert_eq!(&buf[14..20], &[0.0, 1.0, 0.0, 0.0, 0.0, 1.0]);115        let glass = 128.0 / 255.0;116        assert_eq!(&buf[20..28], &[0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, glass]);117        assert_eq!(&buf[28..36], &[0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, glass]);118    }119    #[test]120    fn the_pack_splits_quads_and_keeps_furniture_still() {121        let mut pack = Pack::new();122        pack.quad(123            [124                Vec3::new(0.0, 0.0, 0.0),125                Vec3::new(1.0, 0.0, 0.0),126                Vec3::new(1.0, 1.0, 0.0),127                Vec3::new(0.0, 1.0, 0.0),128            ],129            Vec3::new(0.0, 0.0, 1.0),130        );131        pack.line(132            Vec3::new(0.0, 0.0, 0.0),133            Vec3::new(1.0, 0.0, 0.0),134            false,135            [0, 0, 0, 255],136        );137        let buf = pack.buffer();138        assert_eq!(buf[0], 36.0);139        assert_eq!(buf[2 + 36 + 3], 0.0);140        assert_eq!(buf[2 + 36 + 8 + 3], 0.0);141    }142    #[test]143    fn the_axes_stand_on_the_floor() {144        let edges = axis_edges([255, 255, 255, 255]);145        assert_eq!(edges.len(), 17);146        assert_eq!(edges[0].ends[0], Vec3::new(0.0, -1.0, 0.0));147        assert_eq!(edges[16].color[3], 64);148    }149    #[test]150    fn the_shader_ships_with_the_wire_format() {151        assert!(MESH_WGSL.contains("fn vs_main"));152        assert!(MESH_WGSL.contains("fn vs_line"));153        assert!(MESH_WGSL.contains("var<uniform>"));154    }155}