cyborg/src/commands.rs

130 lines
3.5 KiB
Rust
Raw Normal View History

2022-02-02 03:28:56 +00:00
use super::scene::MeshInstance;
2022-01-31 18:46:06 +00:00
use std::collections::HashMap;
2022-02-02 03:02:17 +00:00
use std::ops::Range;
2022-01-31 18:46:06 +00:00
2022-02-02 03:02:17 +00:00
#[derive(Clone)]
struct DrawState {
group_id: usize,
2022-02-02 23:08:53 +00:00
material_id: usize,
2022-02-02 03:02:17 +00:00
sub_id: usize,
instance_range: Range<u32>,
}
pub enum Command {
BindMeshGroup {
group_id: usize,
},
2022-02-02 23:08:53 +00:00
BindMaterial {
material_id: usize,
2022-02-02 03:02:17 +00:00
},
Draw {
sub_id: usize,
instance_range: Range<u32>,
},
}
pub struct CommandIterator<'a> {
command_set: &'a CommandSet,
command_idx: usize, // TODO use iterator instead lol
last_group_id: usize,
2022-02-02 23:08:53 +00:00
last_material_id: usize,
2022-02-02 03:02:17 +00:00
}
impl<'a> CommandIterator<'a> {
pub fn new(command_set: &'a CommandSet) -> Self {
Self {
command_set,
command_idx: 0,
last_group_id: usize::MAX,
2022-02-02 23:08:53 +00:00
last_material_id: usize::MAX,
2022-02-02 03:02:17 +00:00
}
}
}
impl<'a> Iterator for CommandIterator<'a> {
type Item = Command;
fn next(&mut self) -> Option<Self::Item> {
let DrawState {
group_id,
sub_id,
2022-02-02 23:08:53 +00:00
material_id,
2022-02-02 03:02:17 +00:00
instance_range,
} = self.command_set.draws.get(self.command_idx)?.clone();
if group_id != self.last_group_id {
self.last_group_id = group_id;
Some(Command::BindMeshGroup { group_id })
2022-02-02 23:08:53 +00:00
} else if material_id != self.last_material_id {
self.last_material_id = material_id;
Some(Command::BindMaterial { material_id })
2022-02-02 03:02:17 +00:00
} else {
self.command_idx += 1;
Some(Command::Draw {
sub_id,
instance_range,
})
}
}
}
pub struct CommandSet {
2022-01-31 18:46:06 +00:00
transforms: Vec<[f32; 16]>,
2022-02-02 03:02:17 +00:00
draws: Vec<DrawState>,
2022-01-31 18:46:06 +00:00
}
2022-02-02 03:02:17 +00:00
impl CommandSet {
2022-02-13 04:57:07 +00:00
pub fn build(instances: &[MeshInstance]) -> Self {
2022-02-01 05:06:52 +00:00
let mut sorted_meshes = HashMap::<(usize, usize), Vec<MeshInstance>>::new();
for instance in instances.iter() {
let group_id = instance.mesh.group_id;
2022-02-02 23:08:53 +00:00
let material_id = instance.material.id;
let key = (group_id, material_id);
2022-02-02 03:02:17 +00:00
if let Some(by_state) = sorted_meshes.get_mut(&key) {
by_state.push(*instance);
2022-01-31 18:46:06 +00:00
} else {
2022-02-01 05:06:52 +00:00
sorted_meshes.insert(key, vec![*instance]);
2022-01-31 18:46:06 +00:00
}
}
let mut transforms = Vec::new();
2022-02-01 05:06:52 +00:00
let mut draws = Vec::new();
2022-01-31 18:46:06 +00:00
2022-02-02 23:08:53 +00:00
for ((group_id, material_id), mut meshes) in sorted_meshes.drain() {
2022-02-02 03:02:17 +00:00
let mut sorted_subs = HashMap::<usize, Vec<MeshInstance>>::new();
for mesh in meshes.drain(..) {
let sub_id = mesh.mesh.sub_id;
if let Some(by_sub) = sorted_subs.get_mut(&sub_id) {
by_sub.push(mesh);
} else {
sorted_subs.insert(sub_id, vec![mesh]);
}
}
for (sub_id, meshes) in sorted_subs.drain() {
let start_idx = transforms.len() as u32;
let as_arrays = meshes.iter().map(|i| i.transform.to_cols_array());
transforms.extend(as_arrays);
let end_idx = transforms.len() as u32;
let instance_range = start_idx..end_idx;
draws.push(DrawState {
group_id,
2022-02-02 23:08:53 +00:00
material_id,
2022-02-02 03:02:17 +00:00
sub_id,
instance_range,
});
}
2022-01-31 18:46:06 +00:00
}
2022-02-01 05:06:52 +00:00
Self { transforms, draws }
2022-01-31 18:46:06 +00:00
}
pub fn get_storage(&self) -> &[u8] {
bytemuck::cast_slice(&self.transforms)
}
2022-02-02 03:02:17 +00:00
pub fn iter(&self) -> CommandIterator {
CommandIterator::new(self)
2022-01-31 18:46:06 +00:00
}
}