Editor for papermario-dx mods
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

add CRDT model types to pm64 crate

+150
+150
crates/pm64/src/model.rs
··· 1 + // SPDX-FileCopyrightText: 2026 Alex Bates <alex@bates64.com> 2 + // 3 + // SPDX-License-Identifier: AGPL-3.0-or-later 4 + 5 + //! CRDT-backed model data for PM64 map geometry. 6 + //! 7 + //! These structs are backed by Loro via the [`loroscope`] macro, so every 8 + //! field change is a CRDT operation suitable for collaborative editing and 9 + //! undo/redo. 10 + 11 + use loroscope::loroscope; 12 + 13 + /// An RGBA color with integer channels (0–255 range by convention). 14 + #[loroscope] 15 + #[derive(Debug)] 16 + pub struct ColorRgba { 17 + /// Red channel. 18 + pub r: i64, 19 + /// Green channel. 20 + pub g: i64, 21 + /// Blue channel. 22 + pub b: i64, 23 + /// Alpha channel. 24 + pub a: i64, 25 + } 26 + 27 + /// A vertex with 3D position and vertex color. 28 + #[loroscope] 29 + #[derive(Debug)] 30 + pub struct Vertex { 31 + /// X position. 32 + pub x: f64, 33 + /// Y position. 34 + pub y: f64, 35 + /// Z position. 36 + pub z: f64, 37 + /// Vertex color. 38 + pub color: ColorRgba, 39 + } 40 + 41 + /// A triangle defined by three vertices. 42 + #[loroscope] 43 + #[derive(Debug)] 44 + pub struct Triangle { 45 + /// First vertex. 46 + pub v0: Vertex, 47 + /// Second vertex. 48 + pub v1: Vertex, 49 + /// Third vertex. 50 + pub v2: Vertex, 51 + } 52 + 53 + /// A named node in the model tree, containing a list of triangles. 54 + #[loroscope] 55 + #[derive(Debug)] 56 + pub struct ModelNode { 57 + /// Display name of this model node. 58 + pub name: String, 59 + /// The triangles that make up this node's geometry. 60 + pub triangles: List<Triangle>, 61 + } 62 + 63 + #[cfg(test)] 64 + mod tests { 65 + #![allow(clippy::unwrap_used, clippy::float_cmp)] 66 + 67 + use loroscope::loroscope; 68 + 69 + use super::*; 70 + 71 + #[loroscope] 72 + struct TestRoot { 73 + pub map_model: Tree<ModelNode>, 74 + } 75 + 76 + #[test] 77 + fn create_model_node_with_triangle() { 78 + let root = TestRoot::new(); 79 + let tree = root.map_model(); 80 + 81 + let (node_id, node) = tree.create_root(); 82 + node.set_name("test_node"); 83 + assert_eq!(node.name(), "test_node"); 84 + 85 + let tri = node.triangles().push_new(); 86 + tri.v0().set_x(0.0); 87 + tri.v0().set_y(0.0); 88 + tri.v0().set_z(0.0); 89 + tri.v0().color().set_r(255); 90 + tri.v0().color().set_g(0); 91 + tri.v0().color().set_b(0); 92 + tri.v0().color().set_a(255); 93 + 94 + tri.v1().set_x(100.0); 95 + tri.v1().set_y(0.0); 96 + tri.v1().set_z(0.0); 97 + 98 + tri.v2().set_x(50.0); 99 + tri.v2().set_y(100.0); 100 + tri.v2().set_z(0.0); 101 + 102 + // Read back 103 + let read_node = tree.get(node_id).unwrap(); 104 + assert_eq!(read_node.name(), "test_node"); 105 + assert_eq!(read_node.triangles().len(), 1); 106 + 107 + let read_tri = read_node.triangles().get(0).unwrap(); 108 + assert_eq!(read_tri.v0().x(), 0.0); 109 + assert_eq!(read_tri.v0().color().r(), 255); 110 + assert_eq!(read_tri.v1().x(), 100.0); 111 + assert_eq!(read_tri.v2().y(), 100.0); 112 + } 113 + 114 + #[test] 115 + fn multiple_triangles_in_node() { 116 + let root = TestRoot::new(); 117 + let tree = root.map_model(); 118 + 119 + let (_id, node) = tree.create_root(); 120 + node.set_name("multi"); 121 + 122 + for i in 0..5 { 123 + let tri = node.triangles().push_new(); 124 + let val = f64::from(i) * 10.0; 125 + tri.v0().set_x(val); 126 + tri.v1().set_y(val); 127 + tri.v2().set_z(val); 128 + } 129 + 130 + assert_eq!(node.triangles().len(), 5); 131 + assert_eq!(node.triangles().get(2).unwrap().v0().x(), 20.0); 132 + assert_eq!(node.triangles().get(4).unwrap().v2().z(), 40.0); 133 + } 134 + 135 + #[test] 136 + fn tree_hierarchy() { 137 + let root = TestRoot::new(); 138 + let tree = root.map_model(); 139 + 140 + let (parent_id, parent) = tree.create_root(); 141 + parent.set_name("parent"); 142 + 143 + let (child_id, child) = tree.create_child(parent_id); 144 + child.set_name("child"); 145 + 146 + assert_eq!(tree.children(parent_id).unwrap().len(), 1); 147 + assert_eq!(tree.children(parent_id).unwrap()[0], child_id); 148 + assert_eq!(tree.get(child_id).unwrap().name(), "child"); 149 + } 150 + }