extern crate nalgebra_glm as glm; use std::mem::ManuallyDrop; use std::pin::Pin; // Used to create an unholy abomination upon which you should not cast your gaze. This ended up // being a necessity due to wanting to keep the code written by students as "straight forward" as // possible. It is very very double plus ungood Rust, and intentionally leaks memory like a sieve. // But it works, and you're more than welcome to pretend it doesn't exist! In case you're curious // about how it works: It allocates memory on the heap (Box), promises to prevent it from being // moved or deallocated until dropped (Pin) and finally prevents the compiler from dropping it // automatically at all (ManuallyDrop). // ... // If that sounds like a janky solution, it's because it is! // Prettier, Rustier and better solutions were tried numerous times, but were all found wanting of // having what I arbitrarily decided to be the required level of "simplicity of use". pub type Node = ManuallyDrop>>; pub struct SceneNode { pub position : glm::Vec3, // Where I should be in relation to my parent pub rotation : glm::Vec3, // How I should be rotated, around the X, the Y and the Z axes pub scale : glm::Vec3, // How I should be scaled pub reference_point : glm::Vec3, // The point I shall rotate and scale about pub vao_id : u32, // What I should draw pub index_count : i32, // How much of it there is to draw pub children: Vec<*mut SceneNode>, // Those I command } impl SceneNode { pub fn new() -> Node { ManuallyDrop::new(Pin::new(Box::new(SceneNode { position : glm::zero(), rotation : glm::zero(), scale : glm::vec3(1.0, 1.0, 1.0), reference_point : glm::zero(), vao_id : 0, index_count : -1, children : vec![], }))) } pub fn from_vao(vao_id: u32, index_count: i32) -> Node { ManuallyDrop::new(Pin::new(Box::new(SceneNode { position : glm::zero(), rotation : glm::zero(), scale : glm::vec3(1.0, 1.0, 1.0), reference_point : glm::zero(), vao_id, index_count, children: vec![], }))) } pub fn add_child(&mut self, child: &SceneNode) { self.children.push(child as *const SceneNode as *mut SceneNode) } #[allow(dead_code)] pub fn get_child(& mut self, index: usize) -> & mut SceneNode { unsafe { &mut (*self.children[index]) } } #[allow(dead_code)] pub fn n_children(&self) -> usize { self.children.len() } #[allow(dead_code)] pub fn print(&self) { println!( "SceneNode {{ VAO: {} Indices: {} Children: {} Position: [{:.2}, {:.2}, {:.2}] Rotation: [{:.2}, {:.2}, {:.2}] Reference: [{:.2}, {:.2}, {:.2}] }}", self.vao_id, self.index_count, self.children.len(), self.position.x, self.position.y, self.position.z, self.rotation.x, self.rotation.y, self.rotation.z, self.reference_point.x, self.reference_point.y, self.reference_point.z, ); } } // You can also use square brackets to access the children of a SceneNode use std::ops::{Index, IndexMut}; impl Index for SceneNode { type Output = SceneNode; fn index(&self, index: usize) -> &SceneNode { unsafe { & *(self.children[index] as *const SceneNode) } } } impl IndexMut for SceneNode { fn index_mut(&mut self, index: usize) -> &mut SceneNode { unsafe { &mut (*self.children[index]) } } }