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}