Skip to main content

mraphics_core/
mesh_pool.rs

1use crate::{MeshHandle, MeshLike, MraphicsID, RenderInstance};
2use std::{any::TypeId, collections::HashMap, mem, ptr};
3
4/// A type-erased container for storing any type that implements [`MeshLike`].
5///
6/// Similar to [`Box<dyn Any>`].
7pub struct MeshBox {
8    data: *mut u8,
9
10    type_id: TypeId,
11
12    size: usize,
13    align: usize,
14    drop_fn: unsafe fn(*mut u8),
15
16    update_fn: unsafe fn(*mut u8),
17    update_instance_fn: unsafe fn(*mut u8, instance: &mut RenderInstance),
18}
19
20impl MeshBox {
21    pub fn new<M: MeshLike + 'static>(mesh: M) -> Self {
22        let layout = std::alloc::Layout::new::<M>();
23        let ptr = unsafe { std::alloc::alloc(layout) };
24
25        unsafe {
26            ptr::write(ptr as *mut M, mesh);
27        }
28
29        Self {
30            data: ptr,
31
32            type_id: TypeId::of::<M>(),
33
34            size: mem::size_of::<M>(),
35            align: mem::align_of::<M>(),
36            drop_fn: |ptr| unsafe {
37                let layout = std::alloc::Layout::new::<M>();
38                ptr::drop_in_place(ptr as *mut M);
39                std::alloc::dealloc(ptr, layout);
40            },
41
42            update_fn: |ptr| unsafe {
43                (&mut *(ptr as *mut M)).update();
44            },
45            update_instance_fn: |ptr, instance| unsafe {
46                (&mut *(ptr as *mut M)).update_instance(instance);
47            },
48        }
49    }
50
51    /// Returns the size in bytes of the stored mesh type.
52    pub fn size(&self) -> usize {
53        self.size
54    }
55
56    /// Returns the alignment requirement of the stored mesh type.
57    pub fn align(&self) -> usize {
58        self.align
59    }
60
61    /// Checks if the stored mesh is of given type `M`.
62    pub fn is<M: MeshLike + 'static>(&self) -> bool {
63        self.type_id == TypeId::of::<M>()
64    }
65
66    /// Attempts to downcast the stored mesh to a reference of given type `M`.
67    /// Returns `Some(&M)` if the types match, `None` otherwise.
68    pub fn downcast_ref<M: MeshLike + 'static>(&self) -> Option<&M> {
69        if self.is::<M>() {
70            Some(self.downcast_ref_unchecked::<M>())
71        } else {
72            None
73        }
74    }
75
76    /// Downcasts the stored mesh to a reference of type `M` without type checking.
77    ///
78    /// # Safety
79    /// Caller must ensure the stored mesh is actually of type `M`.
80    /// Incorrect usage leads to undefined behavior.
81    pub fn downcast_ref_unchecked<M: MeshLike + 'static>(&self) -> &M {
82        unsafe { &*(self.data as *const M) }
83    }
84
85    /// Attempts to downcast the stored mesh to a mutable reference of given type `M`.
86    /// Returns `Some(&mut M)` if the types match, `None` otherwise.
87    pub fn downcast_mut<M: MeshLike + 'static>(&mut self) -> Option<&mut M> {
88        if self.is::<M>() {
89            Some(self.downcast_mut_unchecked::<M>())
90        } else {
91            None
92        }
93    }
94
95    /// Downcasts the stored mesh to a mutable reference of type `M` without type checking.
96    ///
97    /// # Safety
98    /// Caller must ensure the stored mesh is actually of type `M`.
99    /// Incorrect usage leads to undefined behavior.
100    pub fn downcast_mut_unchecked<M: MeshLike + 'static>(&mut self) -> &mut M {
101        unsafe { &mut *(self.data as *mut M) }
102    }
103
104    /// Triggers [`MeshLike::update`] for the stored mesh.
105    pub fn update_mesh(&mut self) {
106        // SAFETY: `self.update_fn` and `self.data` are initialized with the same type in [`MeshBox::new`],
107        // and the only way to build a [`MeshBox`] is by using [`MeshBox::new`]
108        unsafe { (self.update_fn)(self.data) }
109    }
110
111    /// Triggers [`InstanceUpdater::update_instance`] for the stored mesh.
112    pub fn update_instance(&mut self, instance: &mut RenderInstance) {
113        // SAFETY: `self.update_instance_fn` and `self.data` are initialized with the same type in [`MeshBox::new`],
114        // and the only way to build a [`MeshBox`] is by using [`MeshBox::new`]
115        unsafe { (self.update_instance_fn)(self.data, instance) }
116    }
117}
118
119impl Drop for MeshBox {
120    fn drop(&mut self) {
121        unsafe { (self.drop_fn)(self.data) }
122    }
123}
124
125pub struct MeshPool {
126    pub meshes: Vec<MeshBox>,
127    mesh_map: HashMap<MraphicsID, usize>,
128}
129
130impl MeshPool {
131    pub fn new() -> Self {
132        Self {
133            meshes: Vec::new(),
134            mesh_map: HashMap::new(),
135        }
136    }
137
138    pub fn add_mesh<M: MeshLike + 'static>(&mut self, mesh: M) -> MeshHandle<M> {
139        let id = mesh.identifier();
140
141        self.meshes.push(MeshBox::new(mesh));
142        self.mesh_map.insert(id, self.meshes.len() - 1);
143
144        MeshHandle::<M>::new(id)
145    }
146
147    /// Triggers [`MeshLike::update`] for the mesh specified by id.
148    pub fn update_mesh(&mut self, id: MraphicsID) {
149        self.meshes[*self.mesh_map.get(&id).unwrap()].update_mesh();
150    }
151
152    /// Updates given [`RenderInstance`] using the mesh specified by id.
153    pub fn update_instance(&mut self, id: MraphicsID, instance: &mut RenderInstance) {
154        self.meshes[*self.mesh_map.get(&id).unwrap()].update_instance(instance);
155    }
156
157    pub fn acquire_mesh<M: MeshLike + 'static>(&self, id: MraphicsID) -> Option<&M> {
158        self.meshes[*self.mesh_map.get(&id).unwrap()].downcast_ref::<M>()
159    }
160
161    pub fn acquire_mesh_unchecked<M: MeshLike + 'static>(&self, id: MraphicsID) -> &M {
162        self.meshes[*self.mesh_map.get(&id).unwrap()]
163            .downcast_ref::<M>()
164            .unwrap()
165    }
166
167    pub fn acquire_mesh_mut<M: MeshLike + 'static>(&mut self, id: MraphicsID) -> Option<&mut M> {
168        self.meshes[*self.mesh_map.get(&id).unwrap()].downcast_mut::<M>()
169    }
170
171    pub fn acquire_mesh_mut_unchecked<M: MeshLike + 'static>(&mut self, id: MraphicsID) -> &mut M {
172        self.meshes[*self.mesh_map.get(&id).unwrap()]
173            .downcast_mut::<M>()
174            .unwrap()
175    }
176}