use std::collections::{HashMap, HashSet};
use crate::entity::RenderEntity;
#[derive(Debug, Default)]
pub struct MeshRenderState {
pub inner: MeshRenderStateInner,
}
#[derive(Debug, Default)]
pub struct MeshRenderStateInner {
pub transform_dirty: HashSet<RenderEntity>,
pub material_dirty: HashSet<RenderEntity>,
pub instanced_local_matrices_dirty: HashSet<RenderEntity>,
pub custom_data_overrides: HashMap<RenderEntity, [f32; 4]>,
pub custom_data_dirty: HashSet<RenderEntity>,
pub object_state_dirty: HashSet<RenderEntity>,
pub instanced_compute_dispatch_needed: bool,
pub instanced_meshes_changed: bool,
pub entities_added: Vec<RenderEntity>,
pub entities_removed: Vec<RenderEntity>,
pub batches_invalidated: bool,
pub full_rebuild_needed: bool,
pub frame_initialized: bool,
}
impl MeshRenderState {
pub fn new() -> Self {
Self {
inner: MeshRenderStateInner {
transform_dirty: HashSet::new(),
material_dirty: HashSet::new(),
instanced_local_matrices_dirty: HashSet::new(),
custom_data_overrides: HashMap::new(),
custom_data_dirty: HashSet::new(),
object_state_dirty: HashSet::new(),
instanced_compute_dispatch_needed: false,
instanced_meshes_changed: false,
entities_added: Vec::new(),
entities_removed: Vec::new(),
batches_invalidated: false,
full_rebuild_needed: true,
frame_initialized: false,
},
}
}
pub fn mark_transform_dirty(&mut self, entity: RenderEntity) {
self.inner.transform_dirty.insert(entity);
}
pub fn mark_object_state_dirty(&mut self, entity: RenderEntity) {
self.inner.object_state_dirty.insert(entity);
}
pub fn mark_instanced_local_matrices_dirty(&mut self, entity: RenderEntity) {
self.inner.instanced_local_matrices_dirty.insert(entity);
}
pub fn mark_instanced_compute_dispatch_needed(&mut self) {
self.inner.instanced_compute_dispatch_needed = true;
}
pub fn mark_instanced_meshes_changed(&mut self) {
self.inner.instanced_meshes_changed = true;
}
pub fn set_entity_custom_data(&mut self, entity: RenderEntity, data: [f32; 4]) {
let old_alpha = self
.inner
.custom_data_overrides
.get(&entity)
.map_or(1.0, |d| d[3]);
if (old_alpha < 1.0) != (data[3] < 1.0) {
self.inner.batches_invalidated = true;
}
self.inner.custom_data_overrides.insert(entity, data);
self.inner.custom_data_dirty.insert(entity);
}
pub fn mark_entity_fade_complete(&mut self, entity: RenderEntity) {
self.inner
.custom_data_overrides
.insert(entity, [1.0, 1.0, 1.0, 1.0]);
self.inner.custom_data_dirty.insert(entity);
self.inner.batches_invalidated = true;
}
pub fn request_full_rebuild(&mut self) {
self.inner.full_rebuild_needed = true;
}
pub fn mark_material_dirty(&mut self, entity: RenderEntity) {
self.inner.material_dirty.insert(entity);
self.inner.batches_invalidated = true;
}
pub fn mark_entity_added(&mut self, entity: RenderEntity) {
self.inner.entities_added.push(entity);
self.inner.batches_invalidated = true;
}
pub fn mark_entity_removed(&mut self, entity: RenderEntity) {
self.inner.entities_removed.push(entity);
self.inner.batches_invalidated = true;
self.inner.transform_dirty.remove(&entity);
self.inner.material_dirty.remove(&entity);
}
pub fn has_any_changes(&self) -> bool {
!self.inner.transform_dirty.is_empty()
|| !self.inner.material_dirty.is_empty()
|| !self.inner.entities_added.is_empty()
|| !self.inner.entities_removed.is_empty()
|| self.inner.batches_invalidated
|| self.inner.full_rebuild_needed
}
pub fn dirty_entities_for_culling(&self) -> impl Iterator<Item = RenderEntity> + '_ {
self.inner
.transform_dirty
.iter()
.chain(self.inner.material_dirty.iter())
.chain(self.inner.entities_added.iter())
.chain(self.inner.object_state_dirty.iter())
.copied()
}
pub fn requires_full_invalidation(&self) -> bool {
self.inner.full_rebuild_needed
|| self.inner.batches_invalidated
|| !self.inner.entities_removed.is_empty()
}
pub fn frame_initialized(&self) -> bool {
self.inner.frame_initialized
}
pub fn full_rebuild_needed(&self) -> bool {
self.inner.full_rebuild_needed
}
pub fn batches_invalidated(&self) -> bool {
self.inner.batches_invalidated
}
pub fn take_frame_state(&mut self) -> MeshRenderStateInner {
std::mem::replace(
&mut self.inner,
MeshRenderStateInner {
frame_initialized: true,
..Default::default()
},
)
}
pub fn restore_unconsumed(&mut self, unconsumed: MeshRenderStateInner) {
let newer = std::mem::replace(&mut self.inner, unconsumed);
self.inner.merge_newer(newer);
}
}
impl MeshRenderStateInner {
pub fn merge_newer(&mut self, newer: MeshRenderStateInner) {
self.transform_dirty.extend(newer.transform_dirty);
self.material_dirty.extend(newer.material_dirty);
self.instanced_local_matrices_dirty
.extend(newer.instanced_local_matrices_dirty);
self.custom_data_overrides
.extend(newer.custom_data_overrides);
self.custom_data_dirty.extend(newer.custom_data_dirty);
self.object_state_dirty.extend(newer.object_state_dirty);
self.instanced_compute_dispatch_needed |= newer.instanced_compute_dispatch_needed;
self.instanced_meshes_changed |= newer.instanced_meshes_changed;
self.entities_added.extend(newer.entities_added);
self.entities_removed.extend(newer.entities_removed);
self.batches_invalidated |= newer.batches_invalidated;
self.full_rebuild_needed |= newer.full_rebuild_needed;
self.frame_initialized |= newer.frame_initialized;
}
}