use super::{Model, ModelData};
use cgmath::{Euler, Rad, Vector3};
use parking_lot::RwLock;
use std::sync::{mpsc::Sender, Arc};
pub struct ModelHandle {
message_handle: Sender<ModelHandleMessage>,
data: Arc<RwLock<ModelData>>,
}
impl ModelHandle {
pub(crate) fn from_model(
model: Arc<Model>,
message_handle: Sender<ModelHandleMessage>,
) -> (Self, u64, Arc<RwLock<ModelData>>) {
let (id, data) = ModelData::new(model);
(
Self {
message_handle,
data: data.clone(),
},
id,
data,
)
}
pub fn position(&self) -> Vector3<f32> {
self.read(|d| d.position)
}
pub fn rotation(&self) -> Euler<Rad<f32>> {
self.read(|d| d.rotation)
}
pub fn scale(&self) -> f32 {
self.read(|d| d.scale)
}
pub fn read<T>(&self, cb: impl FnOnce(&ModelData) -> T) -> T {
let data = self.data.read();
cb(&data)
}
pub fn modify<T>(&self, cb: impl FnOnce(&mut ModelData) -> T) -> T {
let mut data = self.data.write();
cb(&mut data)
}
}
impl Clone for ModelHandle {
fn clone(&self) -> Self {
let data = self.data.read();
let model = data.model.clone();
let (new_handle, new_id, new_data) =
ModelHandle::from_model(model, self.message_handle.clone());
{
let mut new_data = new_data.write();
new_data.position = data.position;
new_data.rotation = data.rotation;
new_data.scale = data.scale;
}
let _ = self
.message_handle
.send(ModelHandleMessage::NewClone(new_id, new_data));
new_handle
}
}
impl Drop for ModelHandle {
fn drop(&mut self) {
let _ = self
.message_handle
.send(ModelHandleMessage::Dropped(self.data.read().id));
}
}
pub enum ModelHandleMessage {
NewClone(u64, Arc<RwLock<ModelData>>),
Dropped(u64),
}