use crate::renderer::*;
pub struct InstancedModelPart<M: Material> {
gm: Gm<InstancedMesh, M>,
animations: Vec<KeyFrameAnimation>,
}
impl<M: Material> InstancedModelPart<M> {
pub fn animations(&self) -> Vec<Option<String>> {
self.animations
.iter()
.map(|animation| animation.name.clone())
.collect()
}
pub fn choose_animation(&mut self, animation_name: Option<&str>) {
if let Some(animation) = self
.animations
.iter()
.find(|a| animation_name == a.name.as_deref())
.cloned()
{
self.set_animation(move |time| animation.transformation(time));
}
}
}
impl<'a, M: Material> IntoIterator for &'a InstancedModelPart<M> {
type Item = &'a dyn Object;
type IntoIter = std::iter::Once<&'a dyn Object>;
fn into_iter(self) -> Self::IntoIter {
self.gm.into_iter()
}
}
use std::ops::Deref;
impl<M: Material> Deref for InstancedModelPart<M> {
type Target = Gm<InstancedMesh, M>;
fn deref(&self) -> &Self::Target {
&self.gm
}
}
impl<M: Material> std::ops::DerefMut for InstancedModelPart<M> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.gm
}
}
impl<M: Material> Geometry for InstancedModelPart<M> {
impl_geometry_body!(deref);
fn animate(&mut self, time: f32) {
self.gm.animate(time)
}
}
impl<M: Material> Object for InstancedModelPart<M> {
impl_object_body!(deref);
}
pub struct InstancedModel<M: Material>(Vec<InstancedModelPart<M>>);
impl<'a, M: Material> IntoIterator for &'a InstancedModel<M> {
type Item = &'a dyn Object;
type IntoIter = std::vec::IntoIter<&'a dyn Object>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
.map(|m| m as &dyn Object)
.collect::<Vec<_>>()
.into_iter()
}
}
impl<M: Material + FromCpuMaterial + Clone + Default> InstancedModel<M> {
pub fn new(
context: &Context,
instances: &Instances,
cpu_model: &CpuModel,
) -> Result<Self, RendererError> {
let materials = cpu_model
.materials
.iter()
.map(|m| M::from_cpu_material(context, m))
.collect::<Vec<_>>();
let mut gms = Vec::new();
for primitive in cpu_model.geometries.iter() {
if let CpuGeometry::Triangles(geometry) = &primitive.geometry {
let material = if let Some(material_index) = primitive.material_index {
materials
.get(material_index)
.ok_or_else(|| {
RendererError::MissingMaterial(
material_index.to_string(),
primitive.name.clone(),
)
})?
.clone()
} else {
M::default()
};
let mut gm = Gm {
geometry: InstancedMesh::new(context, instances, geometry),
material,
};
gm.set_transformation(primitive.transformation);
gms.push(InstancedModelPart {
gm,
animations: primitive.animations.clone(),
});
}
}
let mut model = Self(gms);
if let Some(animation_name) = model.animations().first().cloned() {
model.choose_animation(animation_name.as_deref());
}
Ok(model)
}
pub fn animations(&self) -> Vec<Option<String>> {
let mut set = std::collections::HashSet::new();
for model_part in self.0.iter() {
set.extend(model_part.animations());
}
set.into_iter().collect()
}
pub fn choose_animation(&mut self, animation_name: Option<&str>) {
for part in self.0.iter_mut() {
part.choose_animation(animation_name);
}
}
pub fn animate(&mut self, time: f32) {
self.iter_mut().for_each(|m| m.animate(time));
}
}
impl<M: Material> std::ops::Deref for InstancedModel<M> {
type Target = Vec<InstancedModelPart<M>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<M: Material> std::ops::DerefMut for InstancedModel<M> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}