use std::collections::HashMap;
use crate::{
custom_index::{AsIndex, NameMap},
data::runtime::{
mesh::MeshIdx,
slot::{SlotIdx, SlotSet},
},
new_index,
};
new_index!(SkinIdx, AttachmentNameIdx, AttachmentDataIdx);
#[derive(Debug, Clone)]
pub struct AttachmentNames {
per_slot: Vec<HashMap<String, AttachmentNameIdx>>,
}
impl AttachmentNames {
pub fn new(slot_count: usize) -> Self {
Self {
per_slot: (0..slot_count).map(|_| HashMap::new()).collect(),
}
}
pub fn intern(&mut self, slot_idx: SlotIdx, name: &str) -> AttachmentNameIdx {
let m = &mut self.per_slot[slot_idx.as_index()];
if let Some(&idx) = m.get(name) {
return idx;
}
let idx = unsafe { AttachmentNameIdx::from_index(m.len()) };
m.insert(name.to_string(), idx);
idx
}
}
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[derive(Debug, Clone, PartialEq)]
pub struct AttachmentData {
pub name: String,
pub mesh: Option<MeshIdx>,
pub color: [f32; 4],
}
#[derive(Debug, Clone)]
pub struct AttachmentSet {
pub data: NameMap<AttachmentDataIdx, AttachmentData>,
}
impl Default for AttachmentSet {
fn default() -> Self {
Self::new()
}
}
impl AttachmentSet {
pub fn new() -> Self {
Self {
data: NameMap::new(),
}
}
pub fn insert(&mut self, name: impl Into<String>, data: AttachmentData) -> AttachmentDataIdx {
self.data.insert(name.into(), data)
}
pub fn get_index(&self, name: &str) -> Option<AttachmentDataIdx> {
self.data.get_index(name)
}
pub fn get_mesh(&self, idx: AttachmentDataIdx) -> Option<MeshIdx> {
self.data[idx].mesh
}
}
#[derive(Debug, Clone)]
pub struct Skin {
pub by_slot: Vec<HashMap<AttachmentNameIdx, AttachmentDataIdx>>,
}
impl Default for Skin {
fn default() -> Self {
Self::new()
}
}
impl Skin {
pub fn new() -> Self {
Self {
by_slot: Vec::new(),
}
}
fn ensure_slot(&mut self, slot_idx: SlotIdx) {
let n = slot_idx.as_index() + 1;
if self.by_slot.len() < n {
self.by_slot.resize_with(n, HashMap::new);
}
}
pub fn insert(
&mut self,
slot_idx: SlotIdx,
name_idx: AttachmentNameIdx,
attachment: AttachmentDataIdx,
) {
self.ensure_slot(slot_idx);
self.by_slot[slot_idx.as_index()].insert(name_idx, attachment);
}
pub fn get(&self, slot_idx: SlotIdx, name_idx: AttachmentNameIdx) -> Option<AttachmentDataIdx> {
self.by_slot
.get(slot_idx.as_index())
.and_then(|m| m.get(&name_idx))
.copied()
}
}
#[derive(Debug, Clone)]
pub struct SkinSet {
pub data: NameMap<SkinIdx, Skin>,
}
impl Default for SkinSet {
fn default() -> Self {
Self::new()
}
}
impl SkinSet {
pub fn new() -> Self {
Self {
data: NameMap::new(),
}
}
pub fn insert(&mut self, name: impl Into<String>, skin: Skin) -> SkinIdx {
self.data.insert(name.into(), skin)
}
pub fn get_index(&self, name: &str) -> Option<SkinIdx> {
self.data.get_index(name)
}
pub fn sample(
&self,
skins: &[SkinIdx],
slots: &SlotSet,
attachment_set: &AttachmentSet,
) -> AttachmentMap {
let mut per_slot = Vec::with_capacity(slots.data.len());
for slot_idx in slots.data.indexs() {
let mut found = None;
if let Some(name_idx) = slots.data[slot_idx].default_attachment_idx {
for &skin_idx in skins {
if let Some(attachment) = self.data[skin_idx].get(slot_idx, name_idx) {
if attachment_set.data[attachment].mesh.is_some() {
found = Some(attachment);
break;
}
}
}
}
per_slot.push(found);
}
AttachmentMap { per_slot }
}
}
#[derive(Debug, Clone, Default)]
pub struct AttachmentMap {
per_slot: Vec<Option<AttachmentDataIdx>>,
}
impl AttachmentMap {
pub fn get(&self, slot: SlotIdx) -> Option<AttachmentDataIdx> {
use crate::custom_index::AsIndex;
self.per_slot.get(slot.as_index()).copied().flatten()
}
pub fn set(&mut self, slot: SlotIdx, attachment: Option<AttachmentDataIdx>) {
use crate::custom_index::AsIndex;
if let Some(v) = self.per_slot.get_mut(slot.as_index()) {
*v = attachment;
} else {
let idx = slot.as_index();
self.per_slot.resize(idx + 1, None);
self.per_slot[idx] = attachment;
}
}
pub fn iter(&self) -> impl Iterator<Item = (SlotIdx, Option<AttachmentDataIdx>)> {
use crate::custom_index::AsIndex;
self.per_slot
.iter()
.copied()
.enumerate()
.map(|(i, a)| (unsafe { SlotIdx::from_index(i) }, a))
}
pub fn iter_with_order(&self, order: &[i32]) -> Vec<(SlotIdx, Option<AttachmentDataIdx>)> {
use crate::custom_index::AsIndex;
order
.iter()
.filter_map(|&i| {
let i = i as usize;
self.per_slot
.get(i)
.copied()
.map(|a| (unsafe { SlotIdx::from_index(i) }, a))
})
.collect()
}
}