use std::{
any::TypeId,
ops::{Deref, DerefMut},
slice::Iter,
};
use bevy::{ecs::system::SystemParam, platform::collections::HashMap, prelude::*};
use any_vec::AnyVec;
use crate::{
prelude::*,
render::{ShapeData, ShapeInstance, ShapePipelineMaterial, ShapePipelineType},
};
#[derive(Resource, Default)]
pub struct ShapeStorage {
shapes: HashMap<(TypeId, ShapePipelineType), AnyVec<dyn Send + Sync>>,
}
impl ShapeStorage {
fn send<T: ShapeData>(&mut self, config: &ShapeConfig, data: T) {
let key = (TypeId::of::<T>(), config.pipeline);
let vec = self
.shapes
.entry(key)
.or_insert_with(AnyVec::new::<ShapeInstance<T>>);
let instance = ShapeInstance {
material: ShapePipelineMaterial::from(config),
origin: config.origin.unwrap_or(config.transform.translation),
data,
};
unsafe {
vec.downcast_mut_unchecked().push(instance);
}
}
pub fn get<T: ShapeData>(
&self,
pipeline: ShapePipelineType,
) -> Option<Iter<'_, ShapeInstance<T>>> {
self.shapes
.get(&(TypeId::of::<T>(), pipeline))
.map(|vec| unsafe { vec.downcast_ref_unchecked::<ShapeInstance<T>>().iter() })
}
fn clear(&mut self) {
self.shapes = HashMap::default();
}
}
pub fn clear_storage(mut storage: ResMut<ShapeStorage>) {
storage.clear();
}
#[derive(SystemParam)]
pub struct ShapePainter<'w, 's> {
config: &'s mut ShapeConfig,
shapes: ResMut<'w, ShapeStorage>,
default_config: Res<'w, BaseShapeConfig>,
}
impl<'w, 's> ShapePainter<'w, 's> {
pub fn config(&self) -> &ShapeConfig {
self.config
}
pub fn set_config(&mut self, config: ShapeConfig) {
*self.config = config;
}
pub fn send<T: ShapeData>(&mut self, data: T) -> &mut Self {
let Self {
config,
shapes: event_writer,
..
} = self;
event_writer.send(config, data);
self
}
pub fn send_with_config<T: ShapeData>(&mut self, config: &ShapeConfig, data: T) -> &mut Self {
self.shapes.send(config, data);
self
}
pub fn with_children(&mut self, spawn_children: impl FnOnce(&mut ShapePainter)) -> &mut Self {
let config = self.config.clone();
spawn_children(self);
*self.config = config;
self
}
pub fn reset(&mut self) {
*self.config = self.default_config.0.clone();
}
}
impl<'w, 's> Deref for ShapePainter<'w, 's> {
type Target = ShapeConfig;
fn deref(&self) -> &Self::Target {
self.config
}
}
impl<'w, 's> DerefMut for ShapePainter<'w, 's> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.config
}
}